Як виявити зміну маршруту в Angular?


428

Я хочу виявити зміну маршруту в моєму AppComponent.

Після цього я перевірю маркер глобального користувача, щоб побачити, чи він увійшов. Тоді я можу перенаправити користувача, якщо він не входив.

Відповіді:


534

У Angular 2 ви можете subscribe(подія Rx) до екземпляра маршрутизатора. Таким чином, ви можете робити такі речі

class MyClass {
  constructor(private router: Router) {
    router.subscribe((val) => /*whatever*/)
  }
}

Редагувати (з rc.1)

class MyClass {
  constructor(private router: Router) {
    router.changes.subscribe((val) => /*whatever*/)
  }
}

Редагувати 2 (з 2.0.0)

див. також: Router.events doc

class MyClass {
  constructor(private router: Router) {
    router.events.subscribe((val) => {
        // see also 
        console.log(val instanceof NavigationEnd) 
    });
  }
}

2
Я можу отримати дані, event._root.children[0].value._routeConfig.dataсподіваюся, що може бути і кращий спосіб
Акшай

6
@Akshay Ви бачили цю статтю Тодда Мотто: [Динамічні назви сторінок у кутовій 2 із подіями маршрутизатора] ( toddmotto.com/dynamic-page-titles-angular-2-router-events )
Богач

10
чому він стріляє 3 рази?
Інструментарій

2
@Toolkit це тому, що подія має 3 стани і успішно змінює URL-адресу. 3 держави - це: "NavigationStart", "NavigationEnd" та "RoutesRecognized"
RicardoGonzales

10
Ви можете легко фільтрувати події за допомогою filterоператора RxJS . router.events.pipe(filter(e => e instanceof NavigationEnd).subscribe((e) => { ... }
Simon_Weaver

314

RxJS 6

router.events.pipe(filter(event => event instanceof NavigationStart))

Завдяки Peilonrayz (див. Коментарі нижче)

новий маршрутизатор> = RC.3

import { Router, NavigationStart, NavigationEnd, NavigationError, NavigationCancel, RoutesRecognized } from '@angular/router';

constructor(router:Router) {
  router.events.forEach((event) => {
    if(event instanceof NavigationStart) {
    }
    // NavigationEnd
    // NavigationCancel
    // NavigationError
    // RoutesRecognized
  });
}

Ви також можете фільтрувати за даною подією:

import 'rxjs/add/operator/filter';

constructor(router:Router) {
  router.events
    .filter(event => event instanceof NavigationStart)
    .subscribe((event:NavigationStart) => {
      // You only receive NavigationStart events
    });
}

Використання pairwiseоператора для отримання попередньої та поточної події також є приємною ідеєю. https://github.com/angular/angular/isissue/11268#issuecomment-244601977

import 'rxjs/add/operator/pairwise';
import { Router } from '@angular/router;

export class AppComponent {
    constructor(private router: Router) {
        this.router.events.pairwise().subscribe((event) => {
            console.log(event);
        });
    };
}

1
@GunterZochbauer замість 'є' я б використав 'instanceof'. І "подія: подія" має бути в дужках. Дякую за це, досить потужна нова функція! Мені це подобається
Максим

2
Це призводить до помилки компіляції у поточних версіяхArgument of type '(event: Event) => void' is not assignable to parameter of type
Rudi Strydom

1
@RudiStrydom & Günter Zöchbauer - Argument of type '(event: Event) => void' is not assignable to parameter of typeпомилка в тому, що у вашому фрагменті фільтра ви підписуєтесь на об’єкт типу Event замість NavigationEvent.
Bonnici

1
Другим зразком має бути NavigationEvent замість події. Також не забудьте імпортувати "Подія як NavigationEvent" з @ angular / router
Мік

1
Підказка про імпорт була для всіх, хто хоче вирішити цю помилку :)
Мік

91

Для Angular 7 хтось повинен написати так:

this.router.events.subscribe((event: Event) => {})


Детальний приклад може бути наступним:

import { Component } from '@angular/core'; 
import { Router, Event, NavigationStart, NavigationEnd, NavigationError } from '@angular/router';

@Component({
    selector: 'app-root',
    template: `<router-outlet></router-outlet>`
})
export class AppComponent {

    constructor(private router: Router) {

        this.router.events.subscribe((event: Event) => {
            if (event instanceof NavigationStart) {
                // Show loading indicator
            }

            if (event instanceof NavigationEnd) {
                // Hide loading indicator
            }

            if (event instanceof NavigationError) {
                // Hide loading indicator

                // Present error to user
                console.log(event.error);
            }
        });

   }
}

2
Це чудово! дуже всебічно! прекрасно працював на Angular 7.
MaylorTaylor

1
Зазвичай навігація займає дуже мало часу, якщо ви використовуєте стратегію попереднього завантаження. З точки зору зручності користування, я б використовував індикатори завантаження лише для запитів на заднім часі, якщо вони взагалі були.
Філ

5
У конструкторі ви не повинні використовувати <це>, ваш випадок призначений для ngOnInit.
Серхіо Рейс

1
Ідеально, як я можу отримати точний param.id URL?
ShibinRagh

2
Рішення не компонент обмежений, він поширюється по всьому додатком, які споживають ресурси
Md . Rafee

54

Кутовий 7 , якщо ви хочете , subscribeщобrouter

import { Router, NavigationEnd } from '@angular/router';

import { filter } from 'rxjs/operators';

constructor(
  private router: Router
) {
  router.events.pipe(
    filter(event => event instanceof NavigationEnd)  
  ).subscribe((event: NavigationEnd) => {
    console.log(event.url);
  });
}

2
вона не фіксує події переадресації
Анандху Аяякумар

40

Кутовий 4.x і вище:

Цього можна досягти, використовуючи властивість URL класу ActivateRoute, як показано нижче,

this.activatedRoute.url.subscribe(url =>{
     console.log(url);
});

Примітка. Вам потрібно імпортувати та вводити постачальника з angular/routerпакета

import { ActivatedRoute } from '@angular/router`

і

constructor(private activatedRoute : ActivatedRoute){  }

18

Маршрутизатор 3.0.0-beta.2 повинен бути

this.router.events.subscribe(path => {
  console.log('path = ', path);
});

що працює для поточного шляху, але що робити з попереднім?
тацу

16

У куті 6 і RxJS6:

import { filter, debounceTime } from 'rxjs/operators';

 this.router.events.pipe(
      filter((event) => event instanceof NavigationEnd),
      debounceTime(40000)
    ).subscribe(
      x => {
      console.log('val',x);
      this.router.navigate(['/']); /*Redirect to Home*/
}
)

3
ви пропустили імпорт для маршрутизатораimport {Router, NavigationEnd} from "@angular/router"
Дамір Бейльханов,

15

Тут відповіді правильні router-deprecated. Для останньої версії router:

this.router.changes.forEach(() => {
    // Do whatever in here
});

або

this.router.changes.subscribe(() => {
     // Do whatever in here
});

Щоб побачити різницю між цими двома, будь ласка, ознайомтесь із цим питанням SO .

Редагувати

Для останнього потрібно зробити:

this.router.events.subscribe(event: Event => {
    // Handle route change
});

Чи надає вона будь-які дані попереднього та поточного маршруту?
akn

routerЗнову був оновлений (я не оновив свій відповідь ще), так що я не знаю , як це для останнього. Для того, про що routerя писав, ти не зміг. @akn
Делі

Чи можете ви надати якийсь контекст для цієї відповіді? які рядки ви замінюєте в інших рішеннях своїми?
Джерард Сімпсон

12

У куті 8 ви повинні робити так this.router.events.subscribe((event: Event) => {})

Приклад:

import { Component } from '@angular/core'; 
import { Router, Event } from '@angular/router';
import { NavigationStart, NavigationError, NavigationEnd } from '@angular/router';

@Component({
    selector: 'app-root',
    template: `<router-outlet></router-outlet>`
})
export class AppComponent {

    constructor(private router: Router) {
        //Router subscriber
        this.router.events.subscribe((event: Event) => {
            if (event instanceof NavigationStart) {
                //do something on start activity
            }

            if (event instanceof NavigationError) {
                // Handle error
                console.error(event.error);
            }

            if (event instanceof NavigationEnd) {
                //do something on end activity
            }
        });
   }
}

10

У компоненті ви можете спробувати це:

import {NavigationEnd, NavigationStart, Router} from '@angular/router';

constructor(private router: Router) {
router.events.subscribe(
        (event) => {
            if (event instanceof NavigationStart)
                // start loading pages
            if (event instanceof NavigationEnd) {
                // end of loading paegs
            }
        });
}

8

Захоплення подій зміни маршруту таким чином ...

import { Component, OnInit, Output, ViewChild } from "@angular/core";
import { Router, NavigationStart, NavigationEnd, Event as NavigationEvent } from '@angular/router';

@Component({
    selector: "my-app",
    templateUrl: "app/app.component.html",
    styleUrls: ["app/app.component.css"]
})
export class AppComponent {

    constructor(private cacheComponentObj: CacheComponent,
        private router: Router) {

        /*  Route event types
            NavigationEnd
            NavigationCancel
            NavigationError
            RoutesRecognized
        */
        router.events.forEach((event: NavigationEvent) => {

            //Before Navigation
            if (event instanceof NavigationStart) {
                switch (event.url) {
                case "/app/home":
                {
                    //Do Work
                    break;
                }
                case "/app/About":
                {
                    //Do Work
                    break;
                }
                }
            }

            //After Navigation
            if (event instanceof NavigationEnd) {
                switch (event.url) {
                case "/app/home":
                {
                    //Do Work
                    break;
                }
                case "/app/About":
                {
                    //Do Work
                    break;
                }
                }
            }
        });
    }
}

Ідеально, як я можу отримати точний param.id URL?
ShibinRagh

6

Місцезнаходження працює ...

import {Component, OnInit} from '@angular/core';
import {Location} from '@angular/common';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit {

    constructor(private location: Location) {
        this.location.onUrlChange(x => this.urlChange(x));
    }

    ngOnInit(): void {}

    urlChange(x) {
        console.log(x);
    }
}

Гарна відповідь. це працює для мого випадку. Спасибі
Умар Тарік

4

вище більшість рішень правильні, але я зіткнувся з проблемою цього випромінювання кілька разів "Навігація випромінювати" event.when я змінив будь-який маршрут, ця подія запускається. Тому чути - це повне рішення для Angular 6.

import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';    

export class FooComponent implements OnInit, OnDestroy {
   private _routerSub = Subscription.EMPTY;
   constructor(private router: Router){}

   ngOnInit(){
     this._routerSub = this.router.events
      .filter(event => event instanceof NavigationEnd)
      .subscribe((value) => {
         //do something with the value
     });
  }

  ngOnDestroy(){
   this._routerSub.unsubscribe();
  }
} 

3

@Ludohen відповідь чудова, але у випадку, якщо ви не хочете використовувати, instanceofскористайтеся наступним

this.router.events.subscribe(event => {
  if(event.constructor.name === "NavigationStart") {
    // do something...
  }
});

таким чином ви можете перевірити поточну назву події як рядок, і якщо подія сталася, ви можете зробити те, що планували виконувати ваші функції.


3
чому б не використовувати безпеку машинопису?
Паскаль

@Pascal чому ненависть? і Eventтип викликає помилку в Atom, тому я не користувався ним
Khaled Al-Ansari

2
@Pascal ні - це кутова проблема, оскільки подія маршрутизатора не є такою ж, як подія браузера, і тому тип події не працюватиме! їм потрібно створити новий інтерфейс для цієї події, я мав би сказати, що з самого початку, але необґрунтоване голосування вниз не допомогло :)
Халед Аль-Ансарі

5
оскільки мінімізація виконується у виробничому коді, вам слід скористатися, instanceOfщоб ваш приклад працював і у виробничому коді. if(event instanceOf NavigationStart) {
Мілан Ярич

1
Має бутиif(event instanceof NavigationStart)
Кетан

1

Я працюю з програмою angular5, і я стикаюся з тим же питанням. коли я проходжу кутову документацію, вони пропонують найкраще рішення для обробки маршрутизатора подій. Перевірте наступну документацію.

Представляє подію, викликану, коли навігація успішно закінчується

Як це використовувати?

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRouteSnapshot, NavigationEnd } from '@angular/router';
@Component({
    selector: 'app-navbar',
    templateUrl: './navbar.component.html',
    styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
    constructor(private router: Router) { }
    ngOnInit(): void {
        //calls this method when navigation ends
        this.router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
                //calls this stuff when navigation ends
                console.log("Event generated");
            }
        });
    }
}

Коли це використовувати?

У моєму випадку мій додаток ділиться загальною інформаційною панеллю для всіх користувачів, таких як користувачі, адміністратори, але мені потрібно показати та приховати деякі параметри навігації відповідно до типів користувача.

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


0

Наведені нижче ТИП роботи і можуть зробити для вас складно.

// in constructor of your app.ts with router and auth services injected
router.subscribe(path => {
    if (!authService.isAuthorised(path)) //whatever your auth service needs
        router.navigate(['/Login']);
    });

На жаль, це перенаправлення пізніше в процесі маршрутизації, ніж я хотів би. onActivate()Початкового цільового компонента викликається перед перенаправленням.

Існує @CanActivateдекоратор, який ви можете використовувати для цільового компонента, але це а) не централізовано та б) не отримує користі від введених послуг.

Було б чудово, якщо хтось може запропонувати кращий спосіб централізованого авторизації маршруту до його здійснення. Я впевнений, що повинен бути кращий спосіб.

Це мій поточний код (як я міг би змінити його, щоб слухати зміну маршруту?):

import {Component, View, bootstrap, bind, provide} from 'angular2/angular2';
import {ROUTER_BINDINGS, RouterOutlet, RouteConfig, RouterLink, ROUTER_PROVIDERS, APP_BASE_HREF} from 'angular2/router';    
import {Location, LocationStrategy, HashLocationStrategy} from 'angular2/router';

import { Todo } from './components/todo/todo';
import { About } from './components/about/about';

@Component({
    selector: 'app'
})

@View({
    template: `
        <div class="container">
            <nav>
                <ul>
                    <li><a [router-link]="['/Home']">Todo</a></li>
                    <li><a [router-link]="['/About']">About</a></li>
                </ul>
            </nav>
            <router-outlet></router-outlet>
        </div>
    `,
    directives: [RouterOutlet, RouterLink]
})

@RouteConfig([
    { path: '/', redirectTo: '/home' },
    { path: '/home', component: Todo, as: 'Home' },
    { path: '/about', component: About, as: 'About' }
])

class AppComponent {    
    constructor(location: Location){
        location.go('/');
    }    
}    
bootstrap(AppComponent, [ROUTER_PROVIDERS, provide(APP_BASE_HREF, {useValue: '/'})]);

Я бачив, як люди розширюють routerOutlet, щоб додати свій код автентифікації, який є одним із способів. Про це говорять на gitHub, але висновку поки немає. Ось такий спосіб Auth0
Денніс Смолек

Спасибі за вашу відповідь. Чи знаєте ви якісь хороші відео для засвоєння програми authService for angular 2?
AngularM


0

Просто внесіть зміни в AppRoutingModule, як

@NgModule({
imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })],
  exports: [RouterModule]
})

0

Кутова 8. Перевірте, чи поточний маршрут є базовим .

  baseroute: boolean;
  constructor(
    private router: Router,
  ) {
    router.events.subscribe((val: any) => {
      if (val.url == "/") {
        this.baseroute = true;
      } else {
        this.baseroute = false;
      }
    });
  }

0

Я б написав щось подібне:

ngOnInit() {
this.routed = this.router.events.map( event => event instanceof NavigationStart )
  .subscribe(() => {
  } );
}

ngOnDestroy() {
this.routed.unsubscribe();
}

-3

проста відповідь для кутового 8. *

constructor(private route:ActivatedRoute) {
  console.log(route);
}

1
Хіба це не виконується лише за інстанцією, це було б: лише один раз !? Це не рішення.
Satria
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.