Router Navigate non chiama ngOnInit quando è nella stessa pagina


89

Sto chiamando router.navigatesulla stessa pagina con alcuni parametri della stringa di query. In questo caso, ngOnInit()non chiama. È di default o devo aggiungere qualcos'altro?

Risposte:


139

Puoi iniettare il ActivatedRoutee iscriverti aparams

constructor(route:ActivatedRoute) {
  route.params.subscribe(val => {
    // put the code from `ngOnInit` here
  });
}

Il router distrugge e ricrea il componente solo quando naviga su un percorso diverso. Quando vengono aggiornati solo i parametri del percorso o i parametri della query ma il percorso è lo stesso, il componente non verrà distrutto e ricreato.

Un modo alternativo per forzare la ricreazione del componente consiste nell'usare una strategia di riutilizzo personalizzata. Vedi anche Angular2 router 2.0.0 non ricarica i componenti quando lo stesso URL viene caricato con parametri diversi? (non sembrano esserci ancora molte informazioni disponibili su come implementarlo)


1
questo abbonamento non funziona si attiverà solo su init
Osanda Wedamulla

@OsandaWedamulla che è specifico per il tuo codice allora. Difficile da dire senza ulteriori dettagli però
Günter Zöchbauer

1
Non è necessario annullare l'iscrizione anche a questo o viene eseguito automaticamente?
rain01

1
@ rain01 come regola pratica dovresti annullare esplicitamente l'iscrizione nel tuo cpde quando ti sei iscritto esplicitamente. Se hai il codice precedente nel tuo componente root, l'annullamento dell'iscrizione è ridondante perché la durata del componente root è solitamente la stessa dell'intera app Angular.
Günter Zöchbauer

Questa soluzione funziona quando combinato con stackoverflow.com/a/47827668/5284473 (o modificando onSameUrlNavigation globalmente).
S. Roose

106

È possibile modificare la strategia di riutilizzo sul router.

constructor(private router: Router) {
    // override the route reuse strategy
    this.router.routeReuseStrategy.shouldReuseRoute = function() {
        return false;
    };
}

2
Questo avvierà il ngInit di ogni componente sulla pagina.
jforjs

3
Bene, @Pascal, mi hai costretto ad accedere a SO solo per votare la tua risposta. Vorrei aggiungere che in angolare 6 è inoltre necessario aggiungere onSameUrlNavigation: 'reload'l'oggetto di configurazione in questo modo: RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'}). Tuttavia, non potrei parlare per altre versioni di Angular.
Hildy

1
@Hildy, sono stata costretta a fare lo stesso :) Grazie @Pascal! se preferisci lambda puoi farlo this.router.routeReuseStrategy.shouldReuseRoute = () => false;
nick

1
@Swaprks ho creato un routing.module.ts e ho inserito il codice come questo costruttore
Pascal

2
@ Swaprks .. Ho un problema simile e vorrei provare la tua risposta sopra. Ma non mi dice molto come principiante in questo campo. Esattamente dove dovrei inserire questo pezzo di codice nel codice? Devo modificare qualcosa nello snippet di codice (ad esempio ´function () ´)? Se hai creato un nuovo file con il nome routing.module.ts, come dovrebbe interagire con altri file? C'è anche un file chiamato app-routing.module.ts che viene creato automaticamente.
edn

24

Angolare 9

Ho usato quanto segue e ha funzionato.

onButtonClick() {
    this.router.routeReuseStrategy.shouldReuseRoute = function () {
        return false;
    }
    this.router.onSameUrlNavigation = 'reload';
    this.router.navigate('/myroute', { queryParams: { index: 1 } });
}

1
Inoltre, usa anche lambda invece di sopra, this.router.routeReuseStrategy.shouldReuseRoute = () => false;
Dhwanil Patel

Lavora in Angular 8.
Kishan Vaishnav

3
Questo cambierebbe il comportamento del router nell'applicazione o si attiverà solo una volta per questo specifico navigate()?
Halfist

Lavora in Angular 9.
Ilija Iličić

9

Probabilmente hai bisogno di ricaricare la pagina? Questa è la mia soluzione: ho cambiato il @NgModule (nel file app-routing.module.ts nel mio caso):

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})] })

Quali sono le "rotte" qui.
Dhwanil Patel

@DhwanilPatel i tuoi percorsi di app Angular. Ad esempio "const routes: Routes = [{path: 'crisis-center', component: CrisisListComponent}, {path: 'heroes', component: HeroListComponent},]" angular.io/guide/router#register-router-and -routes
Dionis Oros

1

NgOnInitverrebbe chiamato una volta quando viene creata un'istanza. Per la stessa istanza NgOnInitnon verrà più richiamata. Per chiamarlo è necessario distruggere l'istanza creata.


1

Sul tuo metodo di navigazione,

this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate(['/document'], {queryParams: {"search": currentSearch}});

1

Ho avuto lo stesso problema, inoltre ho ricevuto l'avviso:

did you forget to call `ngZone.run()`

Questo sito ha fornito la migliore soluzione:

import { Router } from '@angular/router';
import { NgZone } from '@angular/core';

...

  constructor(
    private ngZone:NgZone,
    private _router: Router
  ){ }

  redirect(to) {
    // call with ngZone, so that ngOnOnit of component is called
    this.ngZone.run(()=>this._router.navigate([to]));
  }

A questo proposito, vorrei sapere come gestire il problema quando si aggiorna semplicemente la pagina con il nuovo percorso. In tal caso, l'avviso NgZone sarà ancora presente.
Siddhant

0

Questo problema deriva probabilmente dal fatto che non stai terminando le tue iscrizioni usando ngOnDestroy. Ecco come fare.

  1. Porta la seguente importazione dell'abbonamento rxjs. import { Subscription } from 'rxjs/Subscription';

  2. Aggiungi OnDestory alla tua importazione Angular Core. import { Component, OnDestroy, OnInit } from '@angular/core';

  3. Aggiungi OnDestory alla tua classe di esportazione. export class DisplayComponent implements OnInit, OnDestroy {

  4. Crea una proprietà oggetto con un valore di Sottoscrizione da rxjs nella tua classe di esportazione per ogni sottoscrizione sul componente. myVariable: Subscription;

  5. Imposta il valore dell'abbonamento su MyVariable: Subscriptions. this.myVariable = this.rmanagerService.getRPDoc(books[i].books.id).subscribe(value => {});

  6. Quindi, proprio sotto ngOninit, posizionare il gancio del ciclo di vita ngOnDestory () e inserire la dichiarazione di annullamento dell'iscrizione per la sottoscrizione. Se ne hai più, aggiungine altri ngOnDestroy() { this.myVariable.unsubscribe(); }


Continuo a digitare al ngOnDestoryposto di ngOnDestroyme stesso ;-)
Simon_Weaver

0

Crea un percorso diverso per lo stesso componente nell'array di route.

route const: Routes = [{path: "app", component: MyComponent}, {path: "app-reload", component: MyComponent}];

Se l'URL corrente è "app", naviga utilizzando "app-reload" e viceversa.


0

Ecco una raccolta delle migliori idee in questa pagina con maggiori informazioni

Soluzione 1: utilizzare l'abbonamento a params:

Tutorial: https://angular-2-training-book.rangle.io/routing/routeparams#reading-route-parameters

Documenti: https://angular.io/api/router/ActivatedRoute#params

In ciascuno dei componenti di instradamento che utilizzano le variabili param includono quanto segue:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';

// ...

@Component({
    // ...
})
export class MyComponent implements OnInit, OnDestroy {
    paramsSub: Subscription;

    // ...

    constructor(activeRoute: ActivatedRoute) {

    }

    public ngOnInit(): void {
        // ...
        this.paramsSub = this.activeRoute.params.subscribe(val => {
            // Handle param values here
        });

        // ...
    }

    // ...

    public ngOnDestroy(): void {
        // Prevent memory leaks
        this.paramsSub.unsubscribe();
    }
}

Alcuni problemi comuni con questo codice sono che gli abbonamenti sono asincroni e possono essere più complicati da gestire. Inoltre non puoi dimenticare di annullare l'iscrizione a ngOnDestroy altrimenti possono accadere cose brutte.

La cosa buona è che questo è il modo più documentato e comune per gestire questo problema. C'è anche un miglioramento delle prestazioni in questo modo poiché stai riutilizzando il modello invece di distruggere e ricreare ogni volta che visiti una pagina.

Soluzione 2 - shouldReuseRoute / onSameUrlNavigation:

Documenti: https://angular.io/api/router/ExtraOptions#onSameUrlNavigation

Documenti: https://angular.io/api/router/RouteReuseStrategy#shouldReuseRoute

Documenti: https://angular.io/api/router/ActivatedRouteSnapshot#params

Trova dove RouterModule.forRootsi trova nel tuo progetto (normalmente si trova in app-routing.module.ts o app.module.ts):

const routes: Routes = [
   // ...
];

// ...

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

Quindi in AppComponent aggiungi quanto segue:

import { Component, OnInit} from '@angular/core';
import { Router } from '@angular/router';

// ...
@Component({
    // ...
})
export class AppComponent implements OnInit {
    constructor(private router: Router) {
    }

    ngOnInit() {
        // Allows for ngOnInit to be called on routing to the same routing Component since we will never reuse a route
        this.router.routeReuseStrategy.shouldReuseRoute = function() {
            return false;
        };

        // ...
    }

    // ...
}

Infine, nei tuoi componenti di routing ora puoi gestire le variabili param in questo modo:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

// ...

@Component({
    // ...
})
export class MyComponent implements OnInit {
    // ...

    constructor(activeRoute: ActivatedRoute) {

    }

    public ngOnInit(): void {
        // Handle params
        const params = +this.activeRoute.snapshot.params;

        // ...
    }

    // ...
}

Problemi comuni con questa soluzione è che non è comune. Inoltre stai modificando il comportamento predefinito del framework Angular, in modo da poter incorrere in problemi in cui le persone normalmente non andrebbero incontro.

La cosa buona è che tutto il tuo codice è sincrono e più facile da capire.


-1

Considera l'idea di spostare il codice che avevi in ​​ngOnInit in ngAfterViewInit. Quest'ultimo sembra essere chiamato sulla navigazione del router e dovrebbe aiutarti in questo caso.


3
non succede davvero
nadav

-7

Quando vuoi usare il router, naviga sulla stessa pagina e vuoi chiamare ngOnInit (), quindi ti piace, ad es.

this.router.navigate (['category / list', category]) .then (() => window.location.reload ());

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.