Bagaimana cara mendeteksi perubahan rute di Angular?


428

Saya mencari untuk mendeteksi perubahan rute di AppComponent.

Setelah itu saya akan memeriksa token pengguna global untuk melihat apakah dia masuk. Lalu saya bisa mengarahkan pengguna jika dia tidak masuk.

Jawaban:


534

Dalam Angular 2 Anda dapat subscribe(acara Rx) ke instance Router. Jadi Anda bisa melakukan hal-hal seperti

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

Edit (sejak rc.1)

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

Edit 2 (sejak 2.0.0)

lihat juga: Router.events doc

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

2
Saya bisa mendapatkan data dengan event._root.children[0].value._routeConfig.datasaya berharap ada cara yang lebih baik
Akshay

6
@Akshay pernahkah Anda melihat artikel ini oleh Todd Motto: [Judul halaman dinamis dalam Angular 2 dengan acara router] ( toddmotto.com/dynamic-page-titles-angular-2-router-events )
Bogac

10
mengapa api 3 kali?
Toolkit

2
@Toolkit karena acara ini memiliki 3 status dan berhasil mengubah url. 3 negara adalah: 'NavigationStart', 'NavigationEnd' dan 'RoutesRecognized'
RicardoGonzales

10
Anda dapat memfilter acara dengan mudah dengan filteroperator RxJS . router.events.pipe(filter(e => e instanceof NavigationEnd).subscribe((e) => { ... }
Simon_Weaver

314

RxJS 6

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

Terima kasih kepada Peilonrayz (lihat komentar di bawah)

router baru> = 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
  });
}

Anda juga dapat memfilter berdasarkan peristiwa yang diberikan:

import 'rxjs/add/operator/filter';

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

Menggunakan pairwiseoperator untuk mendapatkan acara sebelumnya dan saat ini juga merupakan ide bagus. 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 bukannya 'adalah' Saya akan menggunakan 'instanceof'. Dan 'event: Event' harus dalam tanda kurung. Terima kasih untuk ini, fitur baru yang sangat kuat! Saya suka
Maxim

2
Ini tidak membuat kesalahan kompilasi pada versi saat iniArgument 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 typekesalahannya adalah karena dalam cuplikan filter Anda, Anda berlangganan objek bertipe Event alih-alih NavigationEvent.
Bonnici

1
Sampel kedua harus Navigasi Acara bukan Acara. Juga jangan lupa untuk mengimpor "Event as NavigationEvent" dari @ angular / router
Mick

1
Petunjuk tentang impor adalah bagi siapa pun yang ingin menyelesaikan kesalahan ini :)
Mick

92

Untuk Angular 7 seseorang harus menulis seperti:

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


Contoh terperinci dapat sebagai berikut:

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
Ini bagus! sangat komprehensif! bekerja dengan sempurna pada Angular 7.
MaylorTaylor

1
Biasanya navigasi itu sendiri membutuhkan waktu sangat sedikit jika Anda menggunakan strategi preloading. Dalam hal kegunaan saya akan menggunakan memuat indikator hanya pada permintaan http backend, jika sama sekali.
Phil

5
Di konstruktor , Anda tidak boleh menggunakan <ini>, kasing Anda untuk ngOnInit.
Sergio Reis

1
Sempurna, Bagaimana saya bisa mendapatkan param.id tepat dari url?
ShibinRagh

2
Solusinya bukan komponen terbatas, itu menyebar ke seluruh aplikasi, menghabiskan sumber daya
Md. Rafee

54

Sudut 7 , jika Anda ingin subscribeuntukrouter

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
itu tidak menangkap acara pengalihan
Anandhu Ajayakumar

40

4.x sudut ke atas:

Ini dapat dicapai menggunakan properti url dari kelas ActivatedRoute seperti di bawah ini,

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

Catatan: Anda perlu mengimpor dan menyuntikkan penyedia dari angular/routerpaket

import { ActivatedRoute } from '@angular/router`

dan

constructor(private activatedRoute : ActivatedRoute){  }

18

Router 3.0.0-beta.2 seharusnya

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

yang berfungsi untuk jalur saat ini tetapi bagaimana dengan sebelumnya?
tatsu

16

Dalam angular 6 dan 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
Anda melewatkan impor untuk Routerimport {Router, NavigationEnd} from "@angular/router"
Damir Beylkhanov

15

Jawabannya di sini benar router-deprecated. Untuk versi terbaru router:

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

atau

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

Untuk melihat perbedaan antara keduanya, silakan lihat pertanyaan SO ini .

Edit

Untuk yang terbaru harus Anda lakukan:

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

Apakah ini memberikan data rute sebelumnya dan saat ini?
akn

The routertelah diperbarui lagi (saya belum memperbarui jawaban saya belum), jadi saya tidak yakin bagaimana itu adalah untuk yang terbaru. Untuk yang routersaya tulis, Anda tidak bisa. @akn
Dehli

Bisakah Anda memberikan beberapa konteks untuk jawaban ini? baris mana yang Anda ganti di solusi lain dengan milik Anda?
Gerard Simpson

12

Di Angular 8 Anda harus suka this.router.events.subscribe((event: Event) => {})

Contoh:

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

Dalam komponen, Anda mungkin ingin mencoba ini:

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

Tangkap acara perubahan rute dengan cara berikut ...

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

Sempurna, Bagaimana saya bisa mendapatkan param.id tepat dari url?
ShibinRagh

6

Lokasi berhasil ...

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

Jawaban bagus. itu bekerja untuk kasus saya. Terima kasih
Umar Tariq

4

di atas sebagian besar solusi yang benar, tetapi saya menghadapi masalah ini memancarkan beberapa kali acara 'Navigasi memancarkan'. Ketika saya mengubah rute apa pun peristiwa ini dipicu. Jadi dengar adalah solusi lengkap untuk 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 jawaban bagus, tetapi jika Anda tidak ingin menggunakan instanceofgunakan yang berikut ini

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

dengan cara ini Anda dapat memeriksa nama acara saat ini sebagai string dan jika acara tersebut terjadi, Anda dapat melakukan apa yang Anda rencanakan untuk dilakukan.


3
mengapa tidak menggunakan keamanan naskah?
Pascal

@Pasal mengapa benci? dan Eventtipe ini menyebabkan kesalahan pada Atom itu sebabnya saya tidak menggunakannya
Khaled Al-Ansari

2
@Pascal no, ini merupakan masalah Angular karena acara router tidak sama dengan acara browser dan itu sebabnya tipe Acara tidak akan berfungsi! mereka perlu membuat antarmuka baru untuk acara ini, saya seharusnya mengatakan itu dari awal tetapi suara tidak masuk akal yang tidak membantu :)
Khaled Al-Ansari

5
karena minifikasi dilakukan dalam kode produksi Anda sebaiknya menggunakan instanceOfsehingga contoh Anda akan bekerja dalam kode produksi juga. if(event instanceOf NavigationStart) {
Milan Jaric

1
Seharusnyaif(event instanceof NavigationStart)
Ketan

1

Saya bekerja dengan aplikasi angular5 dan saya menghadapi masalah yang sama. ketika saya pergi melalui Dokumentasi Sudut mereka memberikan solusi terbaik untuk menangani peristiwa router. periksa dokumentasi berikut.

Merupakan acara yang dipicu ketika navigasi berakhir dengan sukses

Bagaimana cara menggunakan ini?

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

Kapan harus menggunakan ini?

Dalam kasus saya, aplikasi saya berbagi dasbor umum untuk semua pengguna seperti pengguna, Admin, tetapi saya perlu menunjukkan dan menyembunyikan beberapa opsi navbar sesuai jenis pengguna.

Itu sebabnya setiap kali perubahan url saya perlu memanggil metode layanan yang mengembalikan informasi pengguna yang masuk sebagai tanggapan saya akan pergi untuk operasi lebih lanjut.


0

JENIS pekerjaan berikut dan mungkin melakukan trik untuk Anda.

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

Sayangnya ini pengalihan kemudian dalam proses routing dari yang saya inginkan. The onActivate()komponen target semula disebut sebelum redirect.

Ada @CanActivatedekorator yang dapat Anda gunakan pada komponen target tetapi ini a) tidak terpusat dan b) tidak mendapat manfaat dari layanan yang disuntikkan.

Alangkah baiknya jika ada yang bisa menyarankan cara yang lebih baik untuk otorisasi rute secara terpusat sebelum dilakukan. Saya yakin pasti ada cara yang lebih baik.

Ini adalah kode saya saat ini (Bagaimana saya mengubahnya untuk mendengarkan perubahan rute?):

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

Saya telah melihat orang memperluas routerOutlet untuk menambahkan kode auth mereka yang merupakan salah satu cara. Ada pembicaraan di gitHub tentang hal itu tetapi belum ada kesimpulan .. Inilah cara Auth0
Dennis Smolek

Terima kasih atas tanggapan Anda. Apakah Anda tahu ada video bagus untuk mempelajari layanan authService untuk angular 2?
AngularM

0

Saya melakukannya seperti ini sejak RC 5

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

0

Buat saja perubahan di AppRoutingModule suka

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

0

Sudut 8. Periksa apakah rute saat ini adalah rute dasar .

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

0

Saya akan menulis sesuatu seperti ini:

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

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

-3

jawaban sederhana untuk Angular 8. *

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

1
Bukankah ini hanya dieksekusi pada instantiasi, itu akan menjadi: hanya sekali !? Ini bukan solusi.
Satria
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.