Содержание

HttpClient и отправка запросов

Вначале рассмотрим выполнение простейших GET-запросов. Пусть у нас есть стандартная структура проекта:


Определим обращение по сети к файлу json, который будет хранить некоторые данные. Папка собственно файлов приложения - это папка src. Поэтому в ней определим новую папку assets. И далее добавим в папку src/assets файл user.json, который будет представлять данные:

{
    "name": "Bob",
    "age": 28
}

Для представления данных в папку src/app добавим новый файл user.ts и определим в нем следующий код:

import { Component, OnInit} from '@angular/core';
import { HttpClient} from '@angular/common/http';
import {User} from './user';
 
@Component({
    selector: 'my-app',
    template: `<div>
                    <p>Имя пользователя: {{user?.name}}</p>
                    <p>Возраст пользователя: {{user?.age}}</p>
               </div>`
})
export class AppComponent implements OnInit { 
 
    user: User;
 
    constructor(private http: HttpClient){}
 
    ngOnInit(){
 
        this.http.get('assets/user.json').subscribe((data:User) => this.user=data);
    }
}

В данном случае в шаблоне выводятся данные объекта User, которые мы хотим получить с сервера. Однако загрузка данных, скажем, в конструкторе компонента не очень желательна. В этом плане метод ngOnInit(), который определен в интерфейсе OnInit и который вызывается при инициализации компонента представляет более предпочтительное место для загрузки данных. В конструкторе же мы просто получаем сервис HttpClient.

Далее в методе ngOnInit() получаем данные из сервиса. Сам метод http.get() возвращает объект Observable<any>. Observable представляет своего рода поток, и для прослушивания событий из этого потока применяется метод subscribe. Этот метод определяет действие над результатом запроса - полученными с сервера данными. В данном случае действие определено в виде стрелочной функции. Причем поскольку между схемой класса User и данными из файла json есть прямое сопоставление, то получаемые данные мы можем определить как объект User, и присвоить их переменной данного класса:

(data:User) => this.user=data

Файл проекта после изменений:

Поскольку файл json представляет вспомогательный файл, то нам надо указать это angular cli в файле angular.json с помощью параметра «assets»: [«src/assets»]:

{
  "version": 1,
  "projects": {
    "helloapp": {
      "projectType": "application",
      "root": "",
      "sourceRoot": "src",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/helloapp",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.json",
            "assets": ["src/assets"],
            "aot": true,
            "optimization": true,
            "outputHashing": "all",
            "sourceMap": false,
            "namedChunks": false,
            "vendorChunk": false,
            "buildOptimizer": true,
            "budgets": [
              {
                "type": "initial",
                "maximumWarning": "2mb",
                "maximumError": "5mb"
              }
            ]
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "helloapp:build"
          }
        }
      }
    }},
  "defaultProject": "helloapp"
}

В итоге при запуске веб-страницы мы увидим загруженные данные из файла user.json.

Создание сервиса

При взаимодействии с сервером, как правило, обращения к серверу происходят не непосредственно из компонента, а из вспомогательных сервисов. Поскольку сервис может определять дополнительную логику обработки полученных с сервера данных, которую могли бы сделать код компонента перегруженным. Кроме того, сервисы могут определять функционал, который будет использоваться несколькими компонентами. Компоненты же выступают в качестве потребителей данных, которые получены от сервисов.

Поэтому для работы с http добавим в папку src/app новый файл http.service.ts со следующим содержимым:

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
 
@Injectable()
export class HttpService{
 
    constructor(private http: HttpClient){ }
 
    getData(){
        return this.http.get('assets/user.json')
    }
}

Для отправки запросов сервис получает объект HttpClient. Поскольку сервис принимает в конструкторе параметр через механизм dependency injection, то к классу применяется декоратор @Injectable.

Для выполнения get-запроса у объекта HttpClient вызывается метод get(), в который передается адрес запроса - в нашем случае json-файл с данными.

Теперь используем этот сервис в компоненте AppComponent:

import { Component, OnInit} from '@angular/core';
import { HttpService} from './http.service';
import {User} from './user';
 
@Component({
    selector: 'my-app',
    template: `<div>
                    <p>Имя пользователя: {{user?.name}}</p>
                    <p>Возраст пользователя: {{user?.age}}</p>
               </div>`,
    providers: [HttpService]
})
export class AppComponent implements OnInit { 
 
    user: User;
 
    constructor(private httpService: HttpService){}
 
    ngOnInit(){
 
        this.httpService.getData().subscribe((data:User) => this.user=data);
    }
}

Загрузка сложных данных

В примерах выше определение json-файла соответствует определению класса User, поэтому простое присвоение this.user=data пройдет успешно. И подобным образом мы можем загружать и другие более сложные данные. Например, определим в папке src/assets файл users.json:

{ 
    "userList":
    [{
        "name": "Bob",
        "age": 28
    },{
        "name": "Tom",
        "age": 45
    },{
        "name": "Alice",
        "age": 32
    }]
}

В итоге структура проекта будет выглядеть следующим образом:



Изменим в классе HttpService адрес загрузки данных:

getData(){
        return this.http.get('assets/users.json')
}

И изменим код компонента:

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>Имя пользователя: {{user?.name}}</p>
                <p>Возраст пользователя: {{user?.age}}</p>
                </li>
            </ul>`,
    providers: [HttpService]
})
export class AppComponent implements OnInit { 
 
    users: User[]=[];
 
    constructor(private httpService: HttpService){}
 
    ngOnInit(){
 
        this.httpService.getData().subscribe(data => this.users=data["userList"]);
    }
}

В данном случае мы хотим получить массив объектов User. Но напрямую данные из users.json не соответствуют массиву. Массив в файле определен по ключу «userList». Поэтому, используя данный ключ, мы достаем нужные данные из ответа сервера: this.users=data[«userList»].