Làm thế nào để phát hiện sự thay đổi tuyến đường trong Angular?


428

Tôi đang tìm kiếm để phát hiện một sự thay đổi tuyến đường trong của tôi AppComponent.

Sau đó tôi sẽ kiểm tra mã thông báo người dùng toàn cầu để xem anh ấy đã đăng nhập chưa. Sau đó tôi có thể chuyển hướng người dùng nếu anh ấy chưa đăng nhập.

Câu trả lời:


534

Trong Angular 2, bạn có thể subscribe(sự kiện Rx) đến một phiên bản Bộ định tuyến. Vì vậy, bạn có thể làm những việc như

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

Chỉnh sửa (kể từ RC.1)

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

Chỉnh sửa 2 (kể từ 2.0.0)

xem thêm: Router.events doc

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

2
Tôi có thể lấy dữ liệu bằng cách event._root.children[0].value._routeConfig.datahy vọng có thể có cách tốt hơn
Akshay

6
@Akshay bạn đã xem bài viết này của Todd Motto: [Tiêu đề trang động trong Angular 2 với các sự kiện của bộ định tuyến] ( babmotto.com/dynamic-page-title-angular-2-router-events )
Bogac

10
Tại sao nó bắn 3 lần?
Bộ công cụ

2
@Toolkit vì sự kiện này có 3 trạng thái và thay đổi thành công url. 3 trạng thái là: 'NavigationStart', 'NavigationEnd' và 'RoutesRecognized'
RicardoGonzales

10
bạn có thể lọc các sự kiện dễ dàng với filtertoán tử RxJS . router.events.pipe(filter(e => e instanceof NavigationEnd).subscribe((e) => { ... }
Simon_Weaver

314

RxJS 6

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

Cảm ơn Peilonrayz (xem bình luận bên dưới)

bộ định tuyến mới> = 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
  });
}

Bạn cũng có thể lọc theo sự kiện đã cho:

import 'rxjs/add/operator/filter';

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

Sử dụng pairwisetoán tử để có được sự kiện trước đó và hiện tại cũng là một ý tưởng hay. https://github.com/angular/angular/issues/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 thay vì 'là' Tôi sẽ sử dụng 'instanceof'. Và "sự kiện: Sự kiện" phải nằm trong ngoặc đơn. Cảm ơn vì điều này, tính năng mới khá mạnh mẽ! Tôi thích nó
Maxim

2
Điều này không gây ra lỗi biên dịch trên các phiên bản hiện tạiArgument 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 typelỗi là do trong đoạn lọc của bạn, bạn đang đăng ký một đối tượng thuộc loại Sự kiện thay vì NavigationEvent.
Bonnici

1
Mẫu thứ hai phải là NavigationEvent thay vì Event. Cũng đừng quên nhập "Sự kiện như NavigationEvent" từ @ angular / bộ định tuyến
Mick

1
Gợi ý về việc nhập là cho bất cứ ai muốn giải quyết lỗi này :)
Mick

92

Đối với Angular 7, ai đó nên viết như sau:

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


Một ví dụ chi tiết có thể như sau:

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
Điều đó thật tuyệt! rất toàn diện! hoạt động hoàn hảo trên Angular 7.
MaylorTaylor

1
Thông thường việc điều hướng sẽ mất rất ít thời gian nếu bạn sử dụng chiến lược tải trước. Về khả năng sử dụng, tôi sẽ chỉ sử dụng các chỉ số tải cho các yêu cầu http phụ trợ, nếu có.
Phil

5
Trong hàm tạo , bạn không nên sử dụng <this>, trường hợp của bạn là dành cho ngOnInit.
Sergio Reis

1
Hoàn hảo, Làm thế nào tôi có thể có được param.id chính xác của url?
ShibinRagh

2
Giải pháp không giới hạn thành phần, nó lan truyền khắp ứng dụng, tiêu tốn tài nguyên
Md. Rafee 23/8/19

54

Góc 7 , nếu bạn muốn 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
nó không nắm bắt được sự kiện chuyển hướng
Anandhu Ajayakumar

40

Góc 4.x trở lên:

Điều này có thể đạt được bằng cách sử dụng thuộc tính url của lớp ActivatedRoute như dưới đây,

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

Lưu ý: Rằng bạn cần nhập và tiêm nhà cung cấp từ angular/routergói

import { ActivatedRoute } from '@angular/router`

constructor(private activatedRoute : ActivatedRoute){  }

18

Bộ định tuyến 3.0.0-beta.2 phải là

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

hoạt động cho đường dẫn hiện tại nhưng trước đây thì sao?
tatsu

16

Trong góc 6 và 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
bạn đã lỡ nhập cho Bộ định tuyếnimport {Router, NavigationEnd} from "@angular/router"
Damir Beylkhanov

15

Các câu trả lời ở đây là chính xác cho router-deprecated. Đối với phiên bản mới nhất của router:

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

hoặc là

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

Để xem sự khác biệt giữa hai người, vui lòng kiểm tra câu hỏi SO này .

Biên tập

Lần gần nhất bạn phải làm:

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

Nó có cung cấp bất kỳ dữ liệu của tuyến đường trước và hiện tại không?
akn

Cái routernày đã được cập nhật lại (tôi chưa cập nhật câu trả lời của mình), vì vậy tôi không chắc nó là bản mới nhất như thế nào. Đối với những routergì tôi đã viết về, bạn không thể. @akn
Dehli

Xin vui lòng bạn có thể cung cấp một số bối cảnh cho câu trả lời này? Những dòng nào bạn thay thế trong các giải pháp khác với của bạn?
Gerard Simpson

12

Trong Angular 8 bạn nên làm như thế nào this.router.events.subscribe((event: Event) => {})

Thí dụ:

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

Trong thành phần, bạn có thể muốn thử điều này:

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

Nắm bắt các sự kiện thay đổi tuyến đường theo cách sau ...

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;
                }
                }
            }
        });
    }
}

Hoàn hảo, Làm thế nào tôi có thể có được param.id chính xác của url?
ShibinRagh

6

Địa điểm hoạt động ...

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);
    }
}

Câu trả lời tốt đẹp. nó hoạt động cho trường hợp của tôi. Cảm ơn
Umar Tariq

4

trên hầu hết các giải pháp đều đúng, nhưng tôi đang gặp phải vấn đề này phát ra nhiều lần sự kiện 'Điều hướng phát ra'. Khi tôi thay đổi bất kỳ tuyến đường nào thì sự kiện này được kích hoạt. Vì vậy, nghe là giải pháp hoàn chỉnh cho 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

Câu trả lời @Ludohen là tuyệt vời, nhưng trong trường hợp bạn không muốn sử instanceofdụng, hãy sử dụng như sau

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

với cách này, bạn có thể kiểm tra tên sự kiện hiện tại dưới dạng chuỗi và nếu sự kiện xảy ra, bạn có thể thực hiện những gì bạn đã lên kế hoạch cho chức năng của mình.


3
Tại sao không sử dụng bản in an toàn?
Pascal

@Pascal tại sao lại ghét? và Eventloại gây ra lỗi trong Atom đó là lý do tại sao tôi không sử dụng nó
Khaled Al-Ansari

2
@Pascal không phải là sự cố Angular vì sự kiện bộ định tuyến không giống với sự kiện trình duyệt và đó là lý do tại sao loại Sự kiện sẽ không hoạt động! họ cần tạo một giao diện mới cho sự kiện này, tôi nên nói rằng ngay từ đầu nhưng việc bỏ phiếu không hợp lý đã không giúp được :)
Khaled Al-Ansari

5
vì việc thu nhỏ được thực hiện trong mã sản xuất, bạn nên sử dụng instanceOfđể ví dụ của bạn cũng hoạt động trong mã sản xuất. if(event instanceOf NavigationStart) {
Milan Jaric

1
Nên làif(event instanceof NavigationStart)
Ketan

1

Tôi đang làm việc với ứng dụng angular5 và tôi đang đối mặt với cùng một vấn đề. Khi tôi đi qua Tài liệu góc, họ cung cấp giải pháp tốt nhất để xử lý các sự kiện của bộ định tuyến. kiểm tra tài liệu sau.

Đại diện cho một sự kiện được kích hoạt khi điều hướng kết thúc thành công

Làm thế nào để sử dụng này?

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");
            }
        });
    }
}

Khi nào sử dụng cái này?

Trong trường hợp của tôi, ứng dụng của tôi chia sẻ bảng điều khiển chung cho tất cả người dùng như người dùng, Quản trị viên, nhưng tôi cần hiển thị và ẩn một số tùy chọn thanh điều hướng theo loại người dùng.

Đó là lý do tại sao bất cứ khi nào url thay đổi, tôi cần gọi phương thức dịch vụ trả về thông tin người dùng đã đăng nhập theo phản hồi tôi sẽ thực hiện các hoạt động tiếp theo.


0

KIND sau đây của công việc và có thể làm khó cho bạn.

// 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']);
    });

Thật không may, điều này chuyển hướng sau này trong quá trình định tuyến hơn tôi muốn. Thành onActivate()phần đích ban đầu được gọi trước khi chuyển hướng.

Đây là một @CanActivate trang trí bạn có thể sử dụng trên thành phần đích nhưng đây là một) không tập trung và b) không được hưởng lợi từ các dịch vụ được tiêm.

Sẽ thật tuyệt nếu ai đó có thể đề xuất một cách tốt hơn để ủy quyền tập trung một tuyến đường trước khi nó được cam kết. Tôi chắc chắn phải có một cách tốt hơn.

Đây là mã hiện tại của tôi (Làm cách nào để thay đổi mã để nghe thay đổi tuyến đường?):

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: '/'})]);

Tôi đã thấy mọi người mở rộng routerOutlet để thêm mã xác thực của họ, đó là một cách. Có cuộc nói chuyện trên gitHub về nó nhưng chưa có kết luận nào .. Đây là cách của Auth0: auth0.com/blog/2015/05/14/ợi
Dennis Smolek

Cảm ơn bạn đã phản hồi của bạn. Bạn có biết video nào hay để học authService cho angular 2 không?
AngularM

0

Tôi làm nó như thế này kể từ RC 5

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

0

Chỉ cần thay đổi trên AppRoutingModule như

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

0

Góc 8. Kiểm tra xem tuyến đường hiện tại có phải là tuyến cơ sở không .

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

0

Tôi sẽ viết một cái gì đó như thế này:

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

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

-3

câu trả lời đơn giản cho Angular 8. *

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

1
Không phải điều này chỉ được thực hiện khi khởi tạo, mà sẽ là: chỉ một lần!? Đây không phải là một giải pháp.
Satria
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.