Якщо ви ще не дуже знайомі з Angular 7, ця стаття наблизить вас до найкращого, що пропонує фреймворк. На прикладі демо-застосунку на Angular, ми познайомимось з Angular Router, а саме з такими складовими:
- RouterOutlet;
- Маршрути та шляхи;
- Навігація.
Також з'ясуємо, як використовувати Angular CLI v7 для створення демо-проекту з роутингом та навігацією. Але спершу, оглянемо важливі фічі останньої версії Angular.
Вітайте Angular 7
Angular підтримує компоненту архітектуру, де кожен компонент — ізольована частина коду, яка контролює певну частину UI застосунку та придатна для повторного використання.
Компонент в Angular — TypeScript клас з декоратором @Component
. Він об'єднує шаблон та CSS стилі, які формують вигляд.
Angular версії 7 був випущений нещодавно. Серед нових фіч інструментів CLI та продуктивності:
- CLI Prompts: поширені команди на зразок
ng add
таng new
тепер пропонують користувачеві обрати функціонал, який слід додати до проекту. Наприклад, роутинг, формат стилів тощо; - Додано прокрутку до Angular Material CDK (Component DevKit);
- Додано підтримку
drag and drop
до Angular Material CDK; - Проекти за замовчуванням підтримують Budget Bundles, які попереджують розробників, якщо розмір їх застосунку перевищує допустимий ліміт. За замовчуванням, попередження виникає, якщо розмір застосунку перевищує 2MB та помилка — якщо 5MB. Ви можете змінити цей діапазон у файлі
angular.json
.
Angular Router
Angular Router — потужний JavaScript роутер, створений командою розробників Angular. Його можна встановити з пакета @angular/router
. Ви отримуєте бібліотеку для роутингу, з якою можна визначити декілька елементів router outlet
, декілька стратегій зіставлення маршруту з рядком запиту, з легкістю отримувати параметри маршруту та використовувати хуки для авторизованого доступу до компонентів.
Angular Router — основа платформи Angular. Роутер дозволяє створювати односторінкові застосунки з кількома представленнями та навігацією ними.
Оглянемо важливі деталі роутера докладніше.
Router-outlet
Router-Outlet — директива з бібліотеки роутера, що визначає місце компонента. Зіставлення маршруту проходить через URL браузера. Ви можете додати декілька outlets
до вашого застосунку на Angular і реалізувати складніші сценарії роутингу.
<router-outlet></router-outlet>
Будь-який зіставлений роутером компонент відображається як sibling-компонент для router-outlet
.
Маршрути та шляхи
Маршрути — об'єкти, що обов'язково вміщують шлях та атрибути компонента (або redirectTo шлях). Шлях належить до частини URL, що визначає унікальне представлення для відображення, а атрибути компонента визначають який компонент Angular буде пов'язаний зі шляхом. З визначенням маршруту через статичний метод RouterModule.forRoot(routes)
Router може перенаправляти користувача до певного представлення.
Кожен маршрут зіставляє URL-шлях з компонентом.
Шлях може бути пустим. Це означає, що він використовується за замовчуванням і, зазвичай, при запуску.
Шлях може приймати шаблон рядка(**
). Роутер обере цей маршрут, якщо URL не збігається з жодним шляхом для визначених маршрутів. Такий підхід можна застосувати для «Not Found» або перенаправлення до певного представлення, якщо не було знайдено відповідності.
Приклад маршруту:
{ path: 'contacts', component: ContactListComponent}
Якщо визначення маршруту наявне у конфігурації роутера, він відобразить ContactListComponent
при переході за URL /contacts
.
Стратегії зіставлення маршрутів
Angular Router передбачає різні стратегії зіставлення маршрутів. За замовчуванням роутер переглядає початок URL та зіставляє його з відповідним маршрутом.
Наприклад, ми можемо записати наш попередній маршрут
{ path: 'contacts', component: ContactListComponent}
таким чином:
{ path: 'contacts',pathMatch: 'prefix', component: ContactListComponent}
Атрибут patchMath
визначає стратегію зіставлення. У нашому прикладі це prefix
.
Інша стратегія — full
. Роутер перевірятиме, щоб шлях повністю збігався з поточним URL браузера:
{ path: 'contacts',pathMatch: 'full', component: ContactListComponent}
Параметри маршруту
Створення маршрутів з параметрами — поширена фіча у веб-застосунках. Angular Router дозволяє отримати доступ до параметрів різними способами:
- Використовуючи сервіс ActivatedRoute;
- Використовуючи ParamMap observable (доступний з v4).
Можна використовувати двокрапку для створення параметрів маршруту. Наприклад, маршрут з параметром id
:
{ path: 'contacts/:id', component: ContactDetailComponent}
Хуки маршрутів
Хуки маршрутів — фіча Angular Router, що дозволяє розробникам виконувати деяку логіку при запиті маршруту. Так ми можемо контролювати доступ користувача. Зазвичай, хуки використовують, щоб перевірити авторизацію користувача перед переходом на сторінку.
Ви можете додати хук маршруту, реалізувавши інтерфейс CanActivate з пакета @angular/router
та розширити метод canActivate()
, який містить логіку доступу. Наприклад, наступний хук завжди дозволяє отримати доступ до маршруту:
class MyGuard implements CanActivate {
canActivate() {
return true;
}
}
Тепер ви можете захистити маршрут з хуком та його атрибутом canActivate
:
{ path: 'contacts/:id, canActivate:[MyGuard], component: ContactDetailComponent}
Директива перенаправлення
В Angular Router передбачено директиву routerLink
для створення посилань перенаправлення. Ця директива приймає шлях, пов'язаний з компонентом, до якого здійснюється перенаправлення. Наприклад:
<a [routerLink]="'/contacts'">Contacts</a>
Декілька outlet
та допоміжні маршрути
Angular Router підтримує декілька елементів outlet
в одному застосунку.
У компонента є основний пов'язаний маршрут, але він також може мати декілька допоміжних. Допоміжні маршрути дозволяють здійснювати перенаправлення декількома маршрутами одночасно.
Для створення такого маршруту, вам знадобиться роутер з визначеним атрибутом name
. Там буде відображатися компонент, пов'язаний з допоміжним маршрутом.
<router-outlet></router-outlet>
<router-outlet name="outlet1"></router-outlet>
- Outlet без атрибута
name
— первинний; - Усі outlet, окрім первинного, повинні визначати атрибут
name
.
Потім за допомогою атрибута outlet
можна вказати де слід відображатися компоненту:
{ path: "contacts", component: ContactListComponent, outlet: "outlet1" }
Створення демо-проекту на Angular 7
Перейдемо до практичного боку роботи з Angular Router. Огляньте демо-проект наживо та його GitHub-репозиторій.
Встановлення Angular CLI v7
Angular CLI вимагає Node 8.9+ з NPM 5.5.1+. Перевірте відповідність цим вимогам, потім виконайте наступну команду, щоб встановити останню версію Angular CLI глобально:
$ npm install -g @angular/cli

Помітьте: Ви можете використовувати sudo
для глобального встановлення. Усе залежить від конфігурації npm
.
Створення проекту
Для створення нового проекту треба виконати наступну команду:
$ ng new angular7-router-demo
CLI запропонує вам додати роутинг (натисніть N
, тому що ми розглянемо як додати роутинг вручну) та визначити формат стилів (оберіть CSS, перший варіант і натисніть Enter
). CLI створить структуру тек з необхідними файлами та встановить потрібні залежності.
Імітуємо бек-енд сервіс
Оскільки у нас немає реального бек-енду для взаємодії, ми зімітуємо його з бібліотекою angular-in-memory-web-api. Це веб API для демо та тестів на Angular, що імітує CRUD-операції через REST API.
Уся суть у перехопленні HttpClient
-запитів, надісланих на віддалений сервер і перенаправленні їх до локального сховища, яке необхідно створити.
Для імітації бек-енду, виконаємо наступні кроки:
- Встановимо модуль
angular-in-memory-web-api
; - Створимо сервіс, що повертає зімітовані дані;
- Налаштуємо застосунок на використання нашого несправжнього бек-енду.
Для встановлення angular-in-memory-web-api
модуля з npm виконайте наступну команду:
$ npm install --save angular-in-memory-web-api
Далі, генеруємо бек-енд сервіс:
$ ng g s backend
Відкриваємо файл src/app/backend.service.ts
та імпортуємо InMemoryDbService
з модуля angular-in-memory-web-api
:
import {InMemoryDbService} from 'angular-in-memory-web-api'
Клас сервісу повинен реалізовувати InMemoryDbService
та перевизначати метод createDb()
:
@Injectable({
providedIn: 'root'
})
export class BackendService implements InMemoryDbService{
constructor() { }
createDb(){
let contacts = [
{ id: 1, name: 'Contact 1', email: 'contact1@email.com' },
{ id: 2, name: 'Contact 2', email: 'contact2@email.com' },
{ id: 3, name: 'Contact 3', email: 'contact3@email.com' },
{ id: 4, name: 'Contact 4', email: 'contact4@email.com' }
];
return {contacts};
}
}
Ми просто створюємо масив контактів та повертаємо його. Кожен контакт повинен мати id.
Наостанок, імпортуйте InMemoryWebApiModule
та наш зімітований бeк-eнд сeрвіс до файлу app.module.ts
.
import { InMemoryWebApiModule } from "angular-in-memory-web-api";
import { BackendService } from "./backend.service";
/* ... */
@NgModule({
declarations: [
/*...*/
],
imports: [
/*...*/
InMemoryWebApiModule.forRoot(BackendService)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Створюємо ContactService
, що інкапсулює логіку роботи з контактами:
$ ng g s contact
Відкриваємо файл src/app/contact.service.ts
і наповнюємо його наступним кодом:
import { Injectable } from '@angular/core';
import { HttpClient } from "@angular/common/http";
@Injectable({
providedIn: 'root'
})
export class ContactService {
API_URL: string = "/api/";
constructor(private http: HttpClient) { }
getContacts(){
return this.http.get(this.API_URL + 'contacts')
}
getContact(contactId){
return this.http.get(`${this.API_URL + 'contacts'}/${contactId}`)
}
}
Ми додали два методи:
getContacts()
— для отримання всіх контактів;getContact()
— для отримання контакту за id;
Ви можете встановити будь-яке значення для API_URL
, тому що ми не працюємо з реальним бек-ендом. Усі запити будуть перехоплені та відправлені до нашого зімітованого сервісу.
Створюємо компоненти Angular
Перш ніж з'ясуємо як використовувати різні фічі роутера, створимо декілька компонентів у нашому проекті.
Перейдіть до термінала та виконайте наступні команди:
$ ng g c contact-list
$ ng g c contact-detail
Так ми згенеруємо компоненти ContactListComponent
та ContactDetailComponent
і додамо їх до основного модуля застосунку.
Налаштування роутингу
У більшості випадків ви будете використовувати Angular CLI для створення проектів з налаштуванням роутингу. Тут ми зробимо все вручну, щоб краще зрозуміти як працює роутинг в Angular.
Додаємо модуль роутингу
Нам слід додати AppRoutingModule, який вміщуватиме маршрути нашого застосунку та router-outlet
, де Angular розмістить компонент, відповідно до URL.
Ми дізнаємось:
- Як створити модуль Angular для роутингу та імпортувати його;
- Як додати маршрути до різних компонентів;
- Як додати
router-outlet
.
Розпочнемо зі створення модуля роутингу у файлі app-routing.module.ts
. У теці src/app
створимо файл:
$ cd angular7-router-demo/src/app
$ touch app-routing.module.ts
Відкрийте файл та додайте наступний код:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Спочатку імпортуємо NgModule
з пакета @angular/core
. Це TypeScript декоратор для створення модуля Angular.
Ми також імпортуємо класи RouterModule
та Routes
з пакета @angular/router
. RouterModule
надає статичні методи, на зразок RouterModule.forRoot()
, для передавання об'єкта конфігурації роутеру.
Далі, визначаємо константний масив маршрутів типу Routes
, що міститиме інформацію про кожен маршрут.
Наостанок, створюємо та експортуємо модуль AppRoutingModule
. Це TypeScript клас з декоратором @NgModule
, який приймає деякий об'єкт метаінформації. В атрибуті imports
об'єкта ми викликаємо статичний метод RouterModule.forRoot(routes)
з масивом маршрутів у якості параметра. У масив exports
додаємо RouterModule
.
Імпортуємо модуль роутингу
Далі, нам необхідно імпортувати цей модуль до основного модуля застосунку, що у файлі src/app/app.module.ts
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Ми імпортуємо AppRoutingModule
з ./app-routing.module
та додаємо його у масив imports
основного модуля.
Додаємо router-outlet
Наостанок, необхідно додати router-outlet
. Відкрийте файл src/app/app.component.html
, що вміщує основний шаблон застосунку та додайте компонент <router-outlet>
:
<router-outlet></router-outlet>
Тут роутер Angular відображатиме компонент, що відповідає поточному шляху браузера.
Нам необхідно виконати усі ці кроки, щоб вручну налаштувати роутинг у проекті на Angular .
Створення маршрутів
Додаємо маршрути до наших двох компонентів. Відкрийте файл src/app/app-routing.module.ts
та додайте наступні маршрути до масиву routes
:
const routes: Routes = [
{path: 'contacts' , component: ContactListComponent},
{path: 'contact/:id' , component: ContactDetailComponent}
];
Обов'язково імпортуйте ці два компоненти до модуля роутингу:
import { ContactListComponent } from './contact-list/contact-list.component';
import { ContactDetailComponent } from './contact-detail/contact-detail.component';
Тепер ми можемо отримати доступ до компонентів за шляхами /contacts
та contact/:id
.
Додаємо посилання перенаправлення
Додамо посилання перенаправлення з директивою routerLink
. Відкрийте src/app/app.component.html
та додайте наступний код у верхню частину router-outlet
.
<h2><a [routerLink] = "'/contacts'">Contacts</a></h2>
Далі нам необхідно відобразити список контактів у ContactListComponent
. Відкрийте src/app/contact-list.component.ts
та додайте цей код:
import { Component, OnInit } from '@angular/core';
import { ContactService } from '../contact.service';
@Component({
selector: 'app-contact-list',
templateUrl: './contact-list.component.html',
styleUrls: ['./contact-list.component.css']
})
export class ContactListComponent implements OnInit {
contacts: any[] = [];
constructor(private contactService: ContactService) { }
ngOnInit() {
this.contactService.getContacts().subscribe((data : any[])=>{
console.log(data);
this.contacts = data;
})
}
}
Для зберігання контактів створюємо масив contacts
. Далі імпортуємо ContactService
та викликаємо метод getContacts()
екземпляра (для події життєвого циклу ngOnInit
), щоб отримати контакти та присвоїти ці значення масиву contacts
.
Далі відкриваємо файл src/app/contact-list/contact-list.component.html
та додаємо:
<table style="width:100%">
<tr>
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</tr>
<tr *ngFor="let contact of contacts" >
<td>{{ contact.name }}</td>
<td>{{ contact.email }}</td>
<td>
<a [routerLink]="['/contact', contact.id]">Go to details</a>
</td>
</tr>
</table>
Перебираємо контакти у циклі та відображаємо Name та Email для кожного. Створюємо посилання для компонента Details кожного контакту з директивою routerLink
.
Компонент виглядатиме так:

Коли ми клікаємо на посилання Go to details
, ми перенаправляємось до ContactDetailsComponent
. Маршрут має параметр id
. Подивимось як отримати доступ до нього з нашого компоненту.
Відкрийте файл src/app/contact-detail/contact-detail.component.ts
та змініть код так:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ContactService } from '../contact.service';
@Component({
selector: 'app-contact-detail',
templateUrl: './contact-detail.component.html',
styleUrls: ['./contact-detail.component.css']
})
export class ContactDetailComponent implements OnInit {
contact: any;
constructor(private contactService: ContactService, private route: ActivatedRoute) { }
ngOnInit() {
this.route.paramMap.subscribe(params => {
console.log(params.get('id'))
this.contactService.getContact(params.get('id')).subscribe(c =>{
console.log(c);
this.contact = c;
})
});
}
}
Ми імпортуємо ContactService
та ActivatedRoute
у компонент. У події життєвого циклу ngOnInit()
отримуємо параметр id
, який буде переданий маршрутом, та використаємо його, щоб отримати детальну інформацію про контакти, які ми присвоїли об'єкту contact
.
Відкрийте файл src/app/contact-detail/contact-detail.component.html
та додайте:
<h1> Contact # {{contact.id}}</h1>
<p>
Name: {{contact.name}}
</p>
<p>
Email: {{contact.email}}
</p>

Якщо ми вперше відвідуємо наш застосунок з 127.0.0.1:4200/
, outlet не відобразить жодного компоненту, тому перейдемо з порожнього шляху до contacts
, додавши наступне до масиву маршрутів:
{path: '', pathMatch: 'full', redirectTo: 'contacts'}
Ми хочемо, щоб була повна відповідність пустому шляху, тому як стратегію зіставлення вказуємо full
.
Ще немає коментарів