angular2-router – Stepan Suvorov Blog https://stepansuvorov.com/blog Release 2.0 Sun, 05 Nov 2017 16:16:43 +0000 en-US hourly 1 https://wordpress.org/?v=6.3.1 Концептуальный разбор маршрутизатора Angular2 с примерами https://stepansuvorov.com/blog/2017/02/%d0%ba%d0%be%d0%bd%d1%86%d0%b5%d0%bf%d1%82%d1%83%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d0%b9-%d1%80%d0%b0%d0%b7%d0%b1%d0%be%d1%80-%d0%bc%d0%b0%d1%80%d1%88%d1%80%d1%83%d1%82%d0%b8%d0%b7%d0%b0%d1%82%d0%be%d1%80/ https://stepansuvorov.com/blog/2017/02/%d0%ba%d0%be%d0%bd%d1%86%d0%b5%d0%bf%d1%82%d1%83%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d0%b9-%d1%80%d0%b0%d0%b7%d0%b1%d0%be%d1%80-%d0%bc%d0%b0%d1%80%d1%88%d1%80%d1%83%d1%82%d0%b8%d0%b7%d0%b0%d1%82%d0%be%d1%80/#comments Sat, 18 Feb 2017 09:32:18 +0000 http://stepansuvorov.com/blog/?p=3217 Continue reading ]]>
  • подключение и базовая настройка
    • use hash
  • стейты (states)
  • специальные директивы роутера
  • параметры стейта
  • параметры запроса(query params)
  • статические параметры стейта
  • перенаправление на другой стейт
  • события (events)
  • хуки (guards)
  • резолв асинхронных данных
  • вложенные стейты (nested states)
  • множественные вью (multiple views)
  • ленивая загрузка (lazy loading)
  • Подключение и базовая настройка

    Для использования маршрутизатора нам необходимо в первую очередь импортировать его модуль:

    import { RouterModule } from '@angular/router'

    и прописать в зависимостях:

    [javascript]
    imports: [

    RouterModule,

    ],
    [/javascript]

    После чего мы можем настроить состояния(стейты). Добавим корневой стейт:

    [javascript]
    const routes = [
    {path: ”, component: HomeComponent},
    ];
    [/javascript]

    синтаксис, как вы видите, довольно простой. Нам достаточно указать путь и компонент, который будет отображаться по этому пути. Можем таким же способом добавить еще один стейт:

    [javascript]
    const routes = [
    {path: ”, component: HomeComponent},
    { path: ‘user’, component: UsersComponent},
    ];
    [/javascript]

    Теперь, чтобы подключить описание стейтов к модулю роутера сделаем:

    [javascript]
    imports: [

    RouterModule.forRoot(routes),

    ],
    [/javascript]

    По умолчанию используются HTML5 пути, но если мы хотим переключить на хеш, то нам нужно указать дополнительный параметр:

    [javascript]
    imports: [

    RouterModule.forRoot(routes, {useHash: true}),

    ],
    [/javascript]

    Специальные директивы роутера

    RouterOutlet – для задание места вывода представления:

    [html]
    <router-outlet></router-outlet>;
    [/html]

    RouterLink – хелпер для удобного вывода ссылки:

    [html]
    <a routerLink="user">User</a>
    [/html]

    RouterLinkActive – для выделения(задания специального css класса) активных(указывающих на текущий стейт) ссылок:

    [html]
    <a routerLink="user" routerLinkActive="active-class">User</a>
    [/html]

    также можно задавать параметр

    [html]
    [routerLinkActiveOptions]="{exact: true}"
    [/html]

    Параметры стейта

    Определяем параметр в настройках стейта:

    [javascript]
    { path: ‘user/:userId’, component: UsersComponent},
    [/javascript]

    Получаем этот параметр с помощью специального сервиса ActivatedRoute:

    [javascript]
    constructor(private route: ActivatedRoute) {
    this.route.params.subscribe(params => console.log(params.userId));
    }
    [/javascript]

    также можно подписаться на конкретный параметр с помощью метода pluck:

    [javascript]
    constructor(private route: ActivatedRoute) {
    this.route.params.pluck(‘userId’).subscribe(userId => console.log(userId));
    }
    [/javascript]

    Параметры запроса(query params)

    Кроме параметров стейта, можем также добавлять в url произвольное количество параметров запроса:

    [html]
    <a routerLink="search" [queryParams]="{ city: ‘Amsterdam’ }">Filter by Amsterdam</a>
    [/html]

    либо если изменяем стейт с помощью метода navigate:

    [javascript]
    this.router.navigate([‘/search’], { queryParams: { city:’Amsterdam’ } });
    [/javascript]

    Чтобы получить параметры стейта подписываемся на queryParams свойство:

    [javascript]
    constructor(private route: ActivatedRoute) {
    this.route.queryParams.subscribe(params => console.log(params.city));
    }
    [/javascript]

    Cтатические параметры стейта

    Стейт также можно дополнять статическими параметрами:

    [javascript]
    { path: ‘user’, component: UsersComponent,
    data: {userName: ‘John’}},
    [/javascript]

    И получить доступ через сервис ActivatedRoute:

    [javascript]
    constructor(private route: ActivatedRoute) {
    this.route.data.subscribe(console.log);
    }
    [/javascript]

    Перенаправление на другой стейт

    Перенаправление может быть либо автоматическим (постоянный редирект) либо условным (по какому-то действию).

    Чтобы сделать автоматический редирект в настройках стейта мы прописываем свойство redirectTo, где указываем стейт, на который хотим перенаправить:

    [javascript]
    const routes = [
    { path: ”, redirectTo: ‘dashboard’, pathMatch: ‘full’ },
    { path: ‘dashboard’, component: DashboardComponent },
    ];
    [/javascript]

    обратите также внимание, что в случае path: ” мы должны указать строгую стратегию разбора URL – pathMatch: ‘full’.

    Для условного перенаправления мы используем методы router.navigate() и router.navigateByUrl():

    [javascript]
    router.navigate([‘users’, userId]);
    router.navigateByUrl(`users/${userId}`);
    [/javascript]

    – отличие только в том, что в первом случае вы подаете как параметр набор команд, а во втором строку URL.

    Cобытия роутера

    Мы можем подписываться не только на данные, но и на события происходящие в роутере, в этом нам поможет сервис Router:

    [javascript]
    constructor(router: Router) {
    router.events.subscribe((event: Event) => {
    if (event instanceof NavigationStart) {
    //…
    }
    });
    }
    [/javascript]

    кроме события NavigationStart мы также можем слушать:

    • NavigationEnd
    • NavigationCancel
    • NavigationError
    • RoutesRecognized

    Хуки (guards)

    На ряду с событиями в роутере есть хуки(guards), которые в отличие от событий выполняются ДО действия и в данном случае мы можем вклиниться в поток выполнения, и если нужно остановить выполнение события.

    Существуют следующие хуки:

    • CanActivate – определяет возможность загрузки стейта

    • CanActivateChild – аналогично предыдущего только для вложенного стейта

    • CanDeactivate – запускается при смене стейта, хорошим примером будет подтверждение не сохраненных данных перед уходом со страницы:

      CanDeactivate(){
            return window.confirm("You have unsaved changes. Still want to leave?");
      }
      
    • CanLoad – определяет может ли стейт быть загружен асинхронно

    • Resolve – для резолвинга данных до загрузки стейта (см. отдельный пункт о резолвинге данных)

    Для реализации хука нам нужно 2 момента: определить его в стейте:

    [javascript]
    { path: ‘user’, component: UsersComponent, canActivate: AuthService},
    [/javascript]

    и создать сам хук-сервис, который будет реализовывать соотвествующий интерфейс:

    [javascript]
    import {CanActivate} from ‘@angular/router’;
    export class AuthService implements CanActivate{
    canActivate(): boolean {
    return true;
    }
    }
    [/javascript]

    В методе canActivate мы можем возвращать как просто булевое значение, так и асинхронные Promise и Observable.

    Резолвинг асинхронных данных

    Для подгрузки асинхронных данных до загрузки стейта также используется хук – Resolve:

    [javascript]
    { path: ‘user’, component: UsersComponent, resolve:{ user: UserDataResolveService }},
    [/javascript]

    теперь создадим резолв-сервис:

    [javascript]
    import { Resolve } from ‘@angular/router’;
    export class UserDataResolveService implements Resolve<any> {
    resolve() {
    return { name: ‘Bob’ };
    }
    }
    [/javascript]

    и можно будет подписаться на эти данные, также как и на статические:

    [javascript]
    constructor(route: ActivatedRoute) {
    route.data.subscribe(data => {
    console.log(data.user);
    });
    }
    [/javascript]

    Вложенные стейты (nested states)

    Для задание вложенных/дочерних стейтов мы используем свойство children, в котором определяем массив:

    [javascript]
    { path: ‘user’, children: [
    {path: ”, component: UserProfileComponent},
    {path: ‘settings’, component: UserSettingsComponent}
    ]},
    [/javascript]

    синтаксис вложенных стейтов идентичен основным. Вложенные стейты также могут иметь свои вложенные.

    Множественные вью (multiple views)

    Роутер ангуляра поддерживает множественные вью, то есть наличие нескольких именованных RouterOutlet компонентов:

    [html]
    <router-outlet></router-outlet>
    <router-outlet name="popup"></router-outlet>
    [/html]

    Неименованный – основной. Теперь для настройки прописываем специальное свойство outlet:

    [javascript]
    { path: ‘user’, component: HomeComponent },
    { path: ‘user’, component: UsersComponent, outlet: ‘popup’},
    [/javascript]

    Ссылка routerLink будет выглядеть для такого случая следующим образом:

    [html]
    <a [routerLink]="[{ outlets: { primary: ‘user’, popup: ‘user’ } }]"></a>
    [/html]

    а если мы хотим деактивировать второстепенный аутлет:

    [html]
    <a [routerLink]="[{ outlets: { popup: null } }]">Close user</a>
    [/html]

    Ленивая загрузка (lazy loading)

    Роутер также дает нам возможность организовать отложенную(ленивую) загрузку модулей. Для этого нам необходимо прописать в стейт специальное свойство loadChildren и указать в нем путь и имя модуля, который собираемся загрузить:

    [javascript]
    { path: ‘lazy’, loadChildren: ‘./lazy/lazy.module#LazyModule’ }
    [/javascript]

    и инициализировать RouterModule внутри LazyModule:

    [javascript]
    const routes: Routes = [
    { path: ”, component: AdminComponent }
    ];

    @NgModule({
    imports: [
    CommonModule,
    RouterModule.forChild(routes)
    ],
    declarations: [AdminComponent]
    })
    export class LazyModule { }
    [/javascript]

    мы можем определить сколько захотим состояний для LazyModule, но я для простоты определил один, который загрузит компонент AdminComponent.

    ]]>
    https://stepansuvorov.com/blog/2017/02/%d0%ba%d0%be%d0%bd%d1%86%d0%b5%d0%bf%d1%82%d1%83%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d0%b9-%d1%80%d0%b0%d0%b7%d0%b1%d0%be%d1%80-%d0%bc%d0%b0%d1%80%d1%88%d1%80%d1%83%d1%82%d0%b8%d0%b7%d0%b0%d1%82%d0%be%d1%80/feed/ 2