Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

HttpClient: отправка данных и ошибки

Чтобы создать запись на сервере, отправляют POST-запрос с данными в теле. Любой запрос может не удаться: нет сети, сервер вернул 404 или 500. Пользователь должен видеть и загрузку, и понятное сообщение об ошибке.

POST-запрос

Добавьте метод в сервис PostApi:

// src/app/post-api.ts
createPost(data: { title: string; body: string }) {
  return this.http.post<Post>(this.url, { ...data, userId: 1 });
}

Второй аргумент post() — тело запроса. HttpClient сам превращает объект в JSON и ставит заголовок Content-Type: application/json. Так же работают put(), patch() и delete().

Вызов из компонента

ng generate component post-form
// src/app/post-form/post-form.ts
import { Component, inject, signal } from '@angular/core';
import { PostApi } from '../post-api';
 
@Component({
  selector: 'app-post-form',
  templateUrl: './post-form.html',
})
export class PostForm {
  private api = inject(PostApi);
  message = signal('');
 
  save(title: string, body: string) {
    this.api.createPost({ title, body }).subscribe((post) => {
      this.message.set(`Статья создана, id = ${post.id}`);
    });
  }
}
<!-- src/app/post-form/post-form.html -->
<input #title placeholder="Заголовок" />
<textarea #body placeholder="Текст"></textarea>
<button (click)="save(title.value, body.value)">Опубликовать</button>
<p>{{ message() }}</p>

После нажатия появится «Статья создана, id = 101». JSONPlaceholder отвечает так, будто сохранил статью, но на самом деле ничего не записывает — для учёбы это удобно.

Загрузка и ошибка

Объект с полями next и error в subscribe() позволяет обработать оба исхода:

// src/app/post-list/post-list.ts
import { Component, OnInit, inject, signal } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { PostApi } from '../post-api';
import { Post } from '../post';
 
@Component({
  selector: 'app-post-list',
  templateUrl: './post-list.html',
})
export class PostList implements OnInit {
  private api = inject(PostApi);
  posts = signal<Post[]>([]);
  loading = signal(true);
  error = signal('');
 
  ngOnInit() {
    this.api.getPosts().subscribe({
      next: (posts) => {
        this.posts.set(posts);
        this.loading.set(false);
      },
      error: (err: HttpErrorResponse) => {
        this.error.set(`Не удалось загрузить статьи (код ${err.status})`);
        this.loading.set(false);
      },
    });
  }
}
<!-- src/app/post-list/post-list.html -->
@if (loading()) {
  <p>Загрузка...</p>
} @else if (error()) {
  <p class="error">{{ error() }}</p>
} @else {
  @for (post of posts(); track post.id) {
    <h3>{{ post.title }}</h3>
  }
}

Чтобы проверить ошибку, поменяйте адрес в сервисе на несуществующий, например /postsx, — появится «Не удалось загрузить статьи (код 404)». Без сети код будет 0.

Запасное значение через catchError

Иногда ошибку лучше обработать в сервисе и вернуть пустой список:

// src/app/post-api.ts
import { catchError, of } from 'rxjs';
 
getPostsSafe() {
  return this.http.get<Post[]>(this.url).pipe(
    catchError(() => of([])),
  );
}

Функция of([]) создаёт Observable с одним значением — пустым массивом. Компонент получит [] и покажет блок @empty.

Частая ошибка

Не обрабатывать ошибку совсем. Тогда при сбое индикатор «Загрузка...» висит вечно, а ошибка видна только в консоли браузера. У каждого запроса, результат которого видит пользователь, должна быть ветка error или оператор catchError.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.