Роутинг в Angular: детальний посібник

14 хв. читання

Якщо ви ще не дуже знайомі з 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
Роутинг в Angular: детальний посібник

Помітьте: Ви можете використовувати sudo для глобального встановлення. Усе залежить від конфігурації npm.

Створення проекту

Для створення нового проекту треба виконати наступну команду:

$ ng new angular7-router-demo

CLI запропонує вам додати роутинг (натисніть N, тому що ми розглянемо як додати роутинг вручну) та визначити формат стилів (оберіть CSS, перший варіант і натисніть Enter). CLI створить структуру тек з необхідними файлами та встановить потрібні залежності.

Імітуємо бек-енд сервіс

Оскільки у нас немає реального бек-енду для взаємодії, ми зімітуємо його з бібліотекою angular-in-memory-web-api. Це веб API для демо та тестів на Angular, що імітує CRUD-операції через REST API.

Уся суть у перехопленні HttpClient-запитів, надісланих на віддалений сервер і перенаправленні їх до локального сховища, яке необхідно створити.

Для імітації бек-енду, виконаємо наступні кроки:

  1. Встановимо модуль angular-in-memory-web-api;
  2. Створимо сервіс, що повертає зімітовані дані;
  3. Налаштуємо застосунок на використання нашого несправжнього бек-енду.

Для встановлення 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.

Компонент виглядатиме так:

Роутинг в Angular: детальний посібник

Коли ми клікаємо на посилання 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>
Роутинг в Angular: детальний посібник

Якщо ми вперше відвідуємо наш застосунок з 127.0.0.1:4200/, outlet не відобразить жодного компоненту, тому перейдемо з порожнього шляху до contacts, додавши наступне до масиву маршрутів:

{path: '', pathMatch: 'full', redirectTo: 'contacts'}  

Ми хочемо, щоб була повна відповідність пустому шляху, тому як стратегію зіставлення вказуємо full.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 4.7K
Приєднався: 10 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація