1. Ссылки

Объект Observable и библиотека RxJS

Методы класса HttpClient после выполнения запроса возвращают объект Observable<any>, который определен в библиотеке RxJS (“Reactive Extensions”). Она не является непосредственно частью Angular, однако широко используется особенно при взаимодействии с сервером по http. Эта библиотека реализует паттерн “асинхронный наблюдатель” (asynchronous observable). Так, выполнение запроса к серверу с помощью класса HttpClient выполняются в асинхронном режиме.

Естественно чтобы задействовать функционал RxJS в приложении, в проект должна быть добавлена соответствующая зависимость rxjs:

{
  "name": "helloapp",
  "version": "1.0.0",
  "description": "First Angular 7 Project",
  "author": "Eugene Popov <metanit.com>",
  "scripts": {
    "dev": "webpack-dev-server --hot --open",
    "build": "webpack"
  },
  "dependencies": {
    "rxjs": "^6.3.3"
    // остальное содержимое секции
  },
  "devDependencies": {
    // содержимое секции
  }
}

Используя специальные методы для объекта Observable, например, map и filter, можно произвести некоторую постобработку полученных от сервера результатов.

Так, возьмем проект из прошлой темы:

Структура приложения

Например, определим в файле users.json данные, которые напрямую не соответствуют массиву объектов User:

{
  "userList": [
    {
      "userName": "Bob",
      "userAge": 28
    },
    {
      "userName": "Tom",
      "userAge": 45
    },
    {
      "userName": "Alice",
      "userAge": 32
    }
  ]
}

В качестве модели данных используем класс User:

export class User {
  name: string
  age: number
}

Определим следующий код сервиса, который будет получать данные из 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('users.json').pipe(
      map(data => {
        let usersList = data['userList']
        return usersList.map(function(user: any) {
          return { name: user.userName, age: 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 { HttpService } from './http.service'
import { User } from './user'

@Component({
  selector: 'my-app',
  template: `
    <ul>
      <li *ngFor="let user of users">
        <p>Имя пользователя: </p>
        <p>Возраст пользователя: </p>
      </li>
    </ul>
  `,
  providers: [HttpService]
})
export class AppComponent implements OnInit {
  users: User[] = []

  constructor(private httpService: HttpService) {}

  ngOnInit() {
    this.httpService.getUsers().subscribe(data => (this.users = data))
  }
}

Ссылки