Подключите сервис к mock API через HttpClient: CRUD, обработка загрузки, пустого и ошибочного состояний.
В этой работе мы учимся «доставать» данные из интернета (точнее — из локального сервера) и показывать их в приложении. Представьте, что ваше приложение — это покупатель в магазине: оно делает заказ (HTTP-запрос) и ждёт посылку (ответ с данными). Всё остальное — это про то, как не запутаться, если магазин закрыт, пуст или ошибся.
provideHttpClient()catchErrorКонтекст. Прежде чем делать запросы, Angular надо сказать: «У нас есть курьер, разреши им пользоваться». Делается это один раз при запуске приложения (в файле, где вызывается bootstrapApplication).
Аналогия из жизни 💡 Это как выдать сотруднику пропуск на курьерскую службу. Без пропуска он не сможет забирать посылки, как бы вы его ни просили.
Пошаговый разбор.
provideHttpClient из Angular.providers при запуске приложения — это и есть «выдача пропуска».Что увидит студент. Сам по себе этот код ничего на экране не рисует. Но если его забыть — все запросы дальше будут падать с ошибкой «No provider for HttpClient».
import { provideHttpClient } from '@angular/common/http';
bootstrapApplication(AppComponent, {
providers: [provideHttpClient()] // "выдаём пропуск" курьеру HttpClient
});
Контекст. Теперь создадим «отдел доставки» — сервис TaskService, который умеет брать задачи, добавлять, менять и удалять их на сервере. В TaskFlow это список дел: каждая задача — отдельная запись.
Аналогия из жизни 💡 CRUD — это четыре действия с заказами в магазине:
• GET — «покажите, что у вас есть» (получить список).
• POST — «приняли новый заказ» (создать).
• PATCH — «поменяйте в заказе одну строку» (обновить часть).
• DELETE — «отмените заказ» (удалить).
Сам сервис — это курьер HttpClient, который везёт заказ.
Пошаговый разбор.
inject(HttpClient) получаем курьера внутрь сервиса.base — путь к задачам на сервере.get/post/patch/delete) по нужному адресу.Что увидит студент. На экране опять ничего не появится — это пока только «инструкции для курьера». Но теперь у приложения есть готовый набор методов, чтобы управлять задачами.
@Injectable({ providedIn: 'root' }) // сервис доступен во всём приложении
export class TaskService {
private http = inject(HttpClient); // наш "курьер"
private base = 'http://localhost:3000/tasks'; // адрес склада задач
// GET: "покажите все задачи"
getAll() { return this.http.get<Task[]>(this.base); }
// POST: "создайте новую задачу" (d — данные новой задачи)
create(d) { return this.http.post<Task>(this.base, d); }
// PATCH: "поменяйте задачу t" (меняем только переданные поля)
update(t) { return this.http.patch<Task>(`${this.base}/${t.id}`, t); }
// DELETE: "удалите задачу с id"
remove(id) { return this.http.delete<void>(`${this.base}/${id}`); }
}
get<Task[]>), и Angular не даст обратиться к полям, которых нет в модели. Это как этикетка на посылке (поле: значение): вы сразу видите, что внутри, и не полезете за тем, чего там нет.Контекст. Сервер может лежать, интернет — отвалиться, а адрес — быть неправильным. Надо не уронить приложение, а аккуратно вернуть пустой список и дать понять, что что-то пошло не так.
Аналогия из жизни 💡 catchError — это сетка безопасности (ловит падение, чтобы не разбить программу). Если курьер споткнулся (сервер ответил ошибкой), он не падает вниз и не ломает всё шоу, а приземляется в сетку и возвращается с пустыми руками, но живой.
Пошаговый разбор.
pipe() — конвейер обработки.catchError ловим ошибку err.of([]) — пустой список как безопасную «подушку».Что увидит студент. Если сервер упал, приложение не «вылетит». Подписчик получит просто пустой массив, и экран останется рабочим.
getAll() {
return this.http.get<Task[]>(this.base).pipe(
catchError(err => { // сетка безопасности
console.error('Ошибка загрузки:', err); // сообщаем разработчику
return of<Task[]>([]); // пустой список вместо падения
})
);
}
catchError ошибка «убьёт» поток, и подписчик никогда не получит ни данных, ни ответа. Как будто курьер ушёл и не вернулся — приложение зависнет в ожидании.Контекст. Компонент должен показать пользователю ровно одно из четырёх «состояний посылки». Это называется конечный автомат: в каждый момент времени экран находится в одном состоянии.
Аналогия из жизни 💡 Три (на самом деле четыре) состояния посылки:
• loading — «посылка в пути», показываем «Загрузка…».
• empty — «пришла, но коробка пустая», пишем «Задач нет».
• success — «пришли ваши задачи», рисуем список.
• error — «посылка потерялась», показываем ошибку.
Как в трекере заказов: нельзя одновременно и «в пути», и «доставлено».
Пошаговый разбор.
State — все допустимые варианты с их данными.state().status по очереди через @if.Что увидит студент. Пока грузится — «Загрузка…». Если пусто — «Задач нет». Если ошибка — красное сообщение. Если всё ок — список задач с галочками.
type State =
| { status: 'loading' } // посылка в пути
| { status: 'empty' } // пришла пустой
| { status: 'success'; tasks: Task[] } // пришли задачи
| { status: 'error'; message: string }; // потерялась
// в шаблоне проверяем статус по очереди
@if (state().status === 'loading') {
<p>Загрузка…</p>
} @else if (state().status === 'error') {
<p>Ошибка: {{ state().message }}</p>
} @else if (state().status === 'empty') {
<p>Задач нет</p>
} @else {
@for (t of state().tasks; track t.id) { <app-task-item [task]="t" /> }
}
completed (выполнена или нет) — это ДАННЫЕ задачи. Не путайте его с фильтром списка 'done': completed говорит «сделана ли эта одна задача», а 'done' — это значение фильтра, показывающее «только выполненные».Контекст. Здесь — упрощённая версия тех же идей на чистом JavaScript и fetch (это «курьер» в обычном JS, без Angular). Вы можете нажать кнопку и увидеть все три состояния своими глазами.
Аналогия из жизни 💡 Песочница — это тренажёр магазина. Нажимаете «Загрузить» — курьер бежит на склад. Если склад работает — приносит товар (список). Если выключить json-server — склад закрыт, и курьер возвращается с «Ошибкой». Если склад пустой — приносит «Задач нет».
Пошаговый разбор.
load().fetch на сервер. Если ответ не ok — бросаем ошибку.catch и показываем «Ошибка» (error).▶️ Что увидит студент. При включённом json-server — список задач с галочками. При выключенном — красная строка «Ошибка: Failed to fetch». При пустой базе — «Задач нет (empty)».
error вживую. Это самый наглядный урок обработки ошибок.PATCH отличается от PUT? (Подсказка: PATCH меняет только часть заказа, PUT — заменяет весь.)catchError возвращает of([]), а не просто []? (Подсказка: поток должен вернуть «посылку-обёртку», а не голые данные.)error.)Практика к уроку 7. Это последняя практическая работа занятия 2. На главную →
| Термин | Жизненная аналогия | Коротко |
|---|---|---|
| HTTP-запрос | Заказ в магазине | Ты подходишь к прилавку и просишь товар (данные). |
| HTTP-статус | Ответ продавца: 200 / 404 / 500 | 200 — «есть», 404 — «нет такого», 500 — «сломался». |
| fetch / HttpClient | Курьер | Везёт твой заказ на склад и обратно с посылкой. |
| catchError | Сетка безопасности | Ловит падение запроса, чтобы не разбить программу. |
| JSON | Этикетка на посылке | Подпись на коробке: что внутри и как это прочитать. |
| loading / empty / error | Три состояния посылки | «в пути» / «пустая коробка» / «потерялась». |
| signal | Группа в мессенджере | При изменении значения все подписчики получают сообщение. |
1. Если сервер недоступен, запрос выдаёт состояние success? Верно или неверно?
Ответ: Неверно. Недоступный сервер — это «посылка потерялась», значит состояние error, как в сетке безопасности catchError.
2. HttpClient — это сам сервер с данными? Верно или неверно?
Ответ: Неверно. HttpClient — это курьер, который везёт заказ туда и обратно. Сам сервер — это склад, а не курьер.
3. JSON похож на этикетку на посылке? Верно или неверно?
Ответ: Верно. JSON — это подпись на коробке: ключ: значение, по которой мы понимаем, что именно лежит внутри посылки.