Angular для початківців: поєднання різних наборів взаємопов’язаних даних для відображення за допомогою RXJS

У цьому прикладі розглядається ситуація, яка часто зустрічається в багатьох додатках, де є два різні, але пов'язані набори даних, які потрібно отримати з різних API та відобразити разом. Важливо, що відображення цих даних повинно бути таким, щоб зв'язок між ними був чітко видимий.

Наприклад, потрібно відобразити основні дані 10 користувачів у таблиці. Ці дані доступні через фіктивний API, а також необхідно показати задачі (ToDos), створені кожним користувачем. Деталі задач доступні через інший API.

Ми створили інтерфейс UserModel для моделювання даних користувачів, що виглядає так:

export interface UserModel {
id: number,
name: string,
username: string,
email: string,
address: AddressModel,
phone: string,
website: string,
company: CompanyModel
}

Також для задач кожного користувача ми створили інтерфейс ToDoModel:

export interface ToDoModel {
userId: number,
id: number,
title: string,
completed: boolean
}

Зв'язок між цими двома наборами даних — це id користувача. Ми відобразимо кілька деталей користувача, таких як id та name у UserModel. Використовуватимемо userId з ToDoModel для отримання задач, створених кожним користувачем.

Нижче представлений скріншот того, що ми хочемо досягти.

pic

Для отримання цих даних ми використовуємо сервіс DataService:

export class DataService{

constructor(private http:HttpClient){}

getUsers():Observable{
return this.http.get < UserModel[]>(‘https://jsonplaceholder.typicode.com/users')
}

getToDos(): Observable{
return this.http.get(‘https://jsonplaceholder.typicode.com/todos')
}

}

У класі AppComponent ми паралельно викликаємо два API за допомогою forkJoin з бібліотеки RXJS в методі ngOnInit:

this.data$ = forkJoin([
this.service.getUsers().pipe(this.handleError().bind(this)),
this.service.getToDos().pipe(this.handleError().bind(this)),
])

Для обробки помилок ми створюємо метод handleError():

handleError() {
let that = this;
return function (observable: Observable) {
return observable.pipe(
catchError((err: HttpErrorResponse) => {
that.errorSub$.next(err.message);
return of(null);
}),
takeUntil(that.destroy$)
);
};
}

У методі map ми об'єднуємо дані від обох API, створюючи новий масив об'єктів, кожен з яких відповідає інтерфейсу UserToDoModel:

map(([users, todos]) => {
let result: UserToDoModel[] = users.map((user: UserModel) => {
return {
userDetail: user,
todos: todos.filter((x: ToDoModel) => x.userId == user.id),
};
});
return result;
}),

Ось інтерфейс UserToDoModel:

export interface UserToDoModel {
userDetail: UserModel;
todos: ToDoModel[];
}

Тепер у нас є масив об'єктів UserToDoModel, який містить інформацію про кожного користувача разом із його задачами.

Ми підписуємося на обсервабель data$ в шаблоні компонента за допомогою async pipe і відображаємо деталі користувачів та їхні задачі.

У результаті ми маємо робочий приклад, де дані користувачів і задач відображаються в таблиці, при цьому зв'язок між ними чітко видно.

Дякуємо, що стали частиною нашої спільноти!

Перекладено з: Angular for Beginners: Combining different sets of related data for display using RXJS