Модуль 2 · урок 15 з 15
Практика модуля
Одна робота, яка закриває всі критерії другої цілі. Тут ти вперше піднімеш реальний Angular-проєкт і перенесеш у нього те, що зверстав у модулі 1. Це найдовша практика в плані — розрахована на кілька вечорів, і поспішати не треба.
Що має вийти
Каркас застосунку: три екрани, навігація між ними, захищена адмінка, типізовані моделі
й нуль any. Даних поки що немає — вони зʼявляться в модулі 4, тому все, що потрібно,
це кілька захардкоджених обʼєктів.
КРОК 1Підняти проєкт
Створи проєкт через CLI зі SCSS. Перевір, що strict і strictTemplates
увімкнені. Заведи структуру папок core, shared, features.
Перенеси токени й скидання стилів із модуля 1 у src/styles/.
Коміт: chore: bootstrap project with strict mode.
КРОК 2Каркас із модуля 1 у компонентах
Розбий свою розмітку на компоненти: app-header, app-sidebar,
і кореневий шаблон із <router-outlet /> усередині робочої області.
Перемикач теми переїжджає в app-header. Усім компонентам одразу постав
ChangeDetectionStrategy.OnPush і :host { display: block } там,
де потрібні розміри.
КРОК 3Моделі й типи
Опиши свої сутності в core/models/: базовий інтерфейс, статус як union
із as const, і похідні типи через utility types — окремо для створення
(Omit), окремо для оновлення (Partial), окремо для рядка списку
(Pick). Додай Record зі словником підписів статусів.
Тут же — DTO і функція-мапер, навіть якщо поки що вони однакові: у модулі 4 це заощадить час.
КРОК 4Роутинг
Три маршрути через loadComponent: список, деталі з параметром :id,
адмінка. Плюс редірект із порожнього шляху й сторінка 404 на '**'.
Увімкни withComponentInputBinding() і прийми id як
input.required. У сайдбарі — routerLink із
routerLinkActive.
КРОК 5Сервіс і DI
Зроби сервіс із providedIn: 'root', який тримає масив захардкоджених сутностей
у сигналі й уміє їх віддавати, додавати й оновлювати. Компоненти отримують його через
inject(). Заведи InjectionToken для конфігу
(наприклад, розмір сторінки) і використай його хоча б в одному місці.
КРОК 6Два guards
CanActivate: адмінка доступна лише з потрібною роллю. Роль поки що з простого сервісу
з сигналом — перемикається кнопкою в шапці, щоб було що показати. При відмові —
createUrlTree на сторінку «немає доступу».
CanDeactivate: на екрані з формою (нехай поки що це просто <input>
з сигналом) — попередження про незбережені зміни через інтерфейс
HasUnsavedChanges.
Логіку рішення винеси в чисті функції — у модулі 8 ти їх протестуєш.
КРОК 7Пайп і директива
Пайп: форматування, яке реально потрібне на екрані — відносна дата, тривалість або підпис статусу. Директива: підсвітка рядків за умовою, автофокус або приховування за роллю. Обидва мають використовуватись у шаблоні, а не лежати «для галочки».
КРОК 8ESLint і нуль any
Додай @angular/eslint, постав no-explicit-any у error
і prefer-on-push-component-change-detection. Прожени ng lint
і почисти все, що знайде. Якщо десь без any ніяк — локальний disable
із коментарем, чому.
- Проєкт на Angular CLI зі strict, у коді рівно нуль
any,ng lintзелений. - Працюють два guards: за роллю й на незбережені зміни.
- Є власні пайп і директива, і вони реально використовуються.
- Моделі побудовані з однієї базової через generics і utility types.
- Усі екрани підключені через
loadComponent. - Усі компоненти на
OnPush.
Що сказати ліду на демо
«Проєкт на strict, лінтер валить збірку на будь-якому any — довелось скрізь
писати чесні типи, зокрема unknown із type guard там, де дані приходять ззовні.
Моделі виведені з однієї базової через Pick, Omit і
Partial, тому нове поле не треба дописувати в пʼяти місцях.
Guards функціональні: за роллю повертає UrlTree, щоб не було двох навігацій одночасно,
а CanDeactivate типізований через інтерфейс, тож працює з будь-яким компонентом
із незбереженими змінами. Логіку рішень винесено в чисті функції — їх зручно тестувати.»
Кроки 1–4 — один-два вечори. Кроки 5–6 — ще два, і саме там буде найбільше нового. Кроки 7–8 — один. Якщо застрягаєш більш ніж на годину в одному місці — це сигнал не «я не розумію», а «варто відкласти й повернутись завтра»: конкретно в DI та guards друга спроба зазвичай коротша за першу.
Далі — модуль 3. Там ти доведеш каркас до вигляду справжнього дашборду й розберешся, як Angular вирішує, що саме перемальовувати. Після цього — модуль 4 із RxJS, і застосунок нарешті отримає дані.