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.

AngularM
sumber

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) 
    });
  }
}
Ludohen
sumber
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);
        });
    };
}
Günter Zöchbauer
sumber
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);
            }
        });

   }
}
Сергій Козюк
sumber
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);
  });
}
Druta Ruslan
sumber
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){  }
Aravind
sumber
18

Router 3.0.0-beta.2 seharusnya

this.router.events.subscribe(path => {
  console.log('path = ', path);
});
Mike Lallemont
sumber
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*/
}
)
JBRandri
sumber
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
});
Dehli
sumber
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
            }
        });
   }
}
Rohit.007
sumber
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
            }
        });
}
mojtaba ramezani
sumber
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;
                }
                }
            }
        });
    }
}
Narottam Goyal
sumber
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);
    }
}
webmaster_sean
sumber
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();
  }
} 
yala ramesh
sumber
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.

Khaled Al-Ansari
sumber
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.

Bhagvat Lande
sumber
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: '/'})]);
Richard Evans
sumber
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
  } );
jirigracik
sumber
0

Buat saja perubahan di AppRoutingModule suka

@NgModule({
imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })],
  exports: [RouterModule]
})
Pullat Junaid
sumber
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;
      }
    });
  }
7guyo
sumber
0

Saya akan menulis sesuatu seperti ini:

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

ngOnDestroy() {
this.routed.unsubscribe();
}
Lalith-AIS
sumber
-3

jawaban sederhana untuk Angular 8. *

constructor(private route:ActivatedRoute) {
  console.log(route);
}
er-Chaan
sumber
1
Bukankah ini hanya dieksekusi pada instantiasi, itu akan menjadi: hanya sekali !? Ini bukan solusi.
Satria