Для взаимодействия с сервером и отправки запросов по протоколу http применяется класс HttpClient. Этот класс определяет ряд методов для отправки различного рода запросов: GET, POST, PUT, DELETE. Данный класс построен поверх стандартного объекта в JavaScript - XMLHttpRequest.
Для использования этого класса в проект необходимо установить пакет "@angular/common":
{ "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": { "@angular/common": "~17.0.0", // остальные пакеты }, "devDependencies": { // остальные пакеты } }
И также в компоненте должен быть импортирован класс HttpClientModule из пакета "@angular/common/http":
import { Component} from "@angular/core"; import { HttpClientModule} from "@angular/common/http"; @Component({ imports: [HttpClientModule],
Вначале рассмотрим выполнение простейших GET-запросов. Пусть у нас есть стандартная структура проекта:
Определим обращение по сети к файлу json, который будет хранить некоторые данные. Папка собственно файлов приложения - это папка src. Поэтому в ней определим новую папку assets. И далее добавим в папку src/assets файл data.json, который будет представлять данные:
{ "name": "Bob", "age": 28 }
Для представления данных в папку src/app добавим новый файл user.ts и определим в нем следующий код:
export class User{ constructor(public name:string, public age:number){} }
Файл проекта после изменений:
Для оправки запроса определим в компоненте AppComponent следующий код:
import { Component, OnInit} from "@angular/core"; import { HttpClient, HttpClientModule} from "@angular/common/http"; import {User} from "./user"; @Component({ selector: "my-app", standalone: true, imports: [HttpClientModule], template: `<div> <p>Имя пользователя: {{user?.name}}</p> <p>Возраст пользователя: {{user?.age}}</p> </div>` }) export class AppComponent implements OnInit { user: User | undefined; constructor(private http: HttpClient){} ngOnInit(){ this.http.get("assets/data.json").subscribe({next:(data:any) => this.user=new User(data.name, data.age)}); } }
В данном случае в шаблоне выводятся данные объекта User, которые мы хотим получить с сервера. Однако загрузка данных, скажем, в конструкторе компонента
не очень желательна. В этом плане метод ngOnInit()
, который определен в интерфейсе OnInit и который вызывается при инициализации компонента представляет
более предпочтительное место для загрузки данных. В конструкторе же мы просто получаем сервис HttpClient.
Далее в методе ngOnInit()
получаем данные из сервиса. Сам метод http.get()
возвращает объект
Observable<Object>. Observable представляет своего рода поток, и для прослушивания событий из этого потока применяется метод subscribe
.
Этот метод определяет действие над результатом запроса - полученными с сервера данными. В данном случае действие определено с помощью параметра next в виде стрелочной функции.
Причем поскольку между схемой класса User и данными из файла json есть прямое сопоставление, то получаемые данные мы можем передать в конструктор класса User:
(data:any) => this.user=new User(data.name, data.age)
Поскольку файл 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": ["zone.js"], "tsConfig": "tsconfig.json", "assets": ["src/assets"], "aot": true } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "buildTarget": "helloapp:build" } } } } } }
В итоге при запуске веб-страницы мы увидим загруженные данные из файла data.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/data.json") } }
Для отправки запросов сервис получает объект HttpClient. К классу применяется декоратор @Injectable
, который гарантирует, что встроенный механизм внедрения
зависимостей сможет создать объект этого класса и передать его в качестве зависимости в другой объект (в другой сервис или компонент).
Для выполнения get-запроса у объекта HttpClient вызывается метод get()
, в который передается адрес запроса - в нашем случае json-файл с данными.
Теперь используем этот сервис в компоненте AppComponent:
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: `<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({next:(data:any) => this.user=new User(data.name, data.age)}); } }
В примерах выше определение json-файла соответствует определению класса User, поэтому простое присвоение this.user=new User(data.name, data.age)
пройдет
успешно. И подобным образом мы можем загружать и другие более сложные данные. Так, изменим файл
data.json следующим образом:
{ "userList": [{ "name": "Bob", "age": 28 },{ "name": "Tom", "age": 45 },{ "name": "Alice", "age": 32 }] }
В классе HttpService также загружаем данные из "data.json":
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/data.json") } }
И изменим код компонента:
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> <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({next: (data: any) => this.users=data["userList"]}); } }
В данном случае мы хотим получить массив объектов User. Но напрямую данные из файла "data.json" не соответствуют массиву. Массив в файле определен по ключу
"userList". Поэтому, используя данный ключ, мы достаем нужные данные из ответа сервера: this.users=data["userList"]
.