Методы класса HttpClient после выполнения запроса возвращают объект Observable<any>, который определен в библиотеке RxJS ("Reactive Extensions"). Она не является непосредственно частью Angular, однако широко используется особенно при взаимодействии с сервером по http. Эта библиотека реализует паттерн "асинхронный наблюдатель" (asynchronous observable). Так, выполнение запроса к серверу с помощью класса HttpClient выполняются в асинхронном режиме.
Естественно чтобы задействовать функционал RxJS в приложении, в проект должна быть добавлена соответствующая зависимость "rxjs":
{ "name": "helloapp", "version": "1.0.0", "description": "First Angular 17 Project", "author": "Eugene Popov <metanit.com>", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build" }, "dependencies": { "rxjs": "~7.8.0", // остальное содержимое секции }, "devDependencies": { // содержимое секции } }
Используя специальные методы для объекта Observable, например, map и filter, можно произвести некоторую постобработку полученных от сервера результатов.
Так, возьмем проект из прошлой темы:
Например, определим в файле data.json данные, которые напрямую не соответствуют массиву объектов User:
{ "userList": [{ "userName": "Bob", "userAge": 28 },{ "userName": "Tom", "userAge": 39 },{ "userName": "Alice", "userAge": 32 }] }
В качестве модели данных используем класс User, определенный в файле user.ts:
export class User{ constructor(public name:string, public age:number){} }
То есть в данном случае у нас нет соответствия по именам свойствам: name - username и age - userage.
Определим следующий код сервиса, который будет получать данные из users.json:
import {Injectable} from "@angular/core"; import {HttpClient} from "@angular/common/http"; import {User} from "./user"; import {Observable} from "rxjs"; import { map } from "rxjs/operators"; @Injectable() export class HttpService{ constructor(private http: HttpClient){ } getUsers() : Observable<User[]> { return this.http.get("assets/data.json").pipe(map((data:any)=>{ let usersList = data["userList"]; return usersList.map(function(user: any): User { return new User(user.userName, user.userAge); }); })); } }
Смысл использования специального сервиса для работы с http заключается в сокрытии деталей отправки запросов. Компонент же ожидает получить какие-то конкретные данные, например, в виде набора объектов User. С помощью метода map библиотеки rxjs можно преобразовать данные из одного формата в другой.
У результата метода get()
мы можем вызвать метод pipe(), который позволяет обработать результаты запроса. Для этого
метод pipe в качестве первого параметра принимает функцию обработки данных запроса. В данном случае в роли такой функции выступает оператор map,
который преобразует результаты запроса в новые объекты.
Но чтобы использовать элементы библиотеки RxJS, их надо импортировать:
import {Observable} from "rxjs"; import { map } from "rxjs/operators";
В итоге весь метод getUsers()
возвращает объект Observable<User[]>
.
Теперь используем сервис в классе компонента:
import { Component, OnInit} from "@angular/core"; import { HttpClientModule} from "@angular/common/http"; import { HttpService} from "./http.service"; import {User} from "./user"; @Component({ selector: "my-app", standalone: true, imports: [HttpClientModule], template: `<ul> @for(user of users; track $index){ <li>{{user?.name}} ({{user?.age}})</li> } </ul>`, providers: [HttpService] }) export class AppComponent implements OnInit { users: User[]=[]; constructor(private httpService: HttpService){} ngOnInit(){ this.httpService.getUsers().subscribe({next:(data: User[]) => this.users=data}); } }