Router Navigate no llama a ngOnInit cuando la misma página

86

Estoy llamando router.navigateen la misma página con algunos parámetros de cadena de consulta. En este caso, ngOnInit()no llama. ¿Es por defecto o necesito agregar algo más?

Jeeten Parmar
fuente

Respuestas:

136

Puede inyectar ActivatedRoutey suscribirse aparams

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

El enrutador solo destruye y recrea el componente cuando navega a una ruta diferente. Cuando solo se actualizan los parámetros de ruta o los parámetros de consulta, pero la ruta es la misma, el componente no se destruirá ni se volverá a crear.

Una forma alternativa de forzar la recreación del componente es utilizar una estrategia de reutilización personalizada. Consulte también el enrutador Angular2 2.0.0 que no recarga componentes cuando la misma URL se carga con diferentes parámetros. (no parece haber mucha información disponible todavía sobre cómo implementarlo)

Günter Zöchbauer
fuente
1
esta suscripción no funciona, solo se activará en init
Osanda Wedamulla
@OsandaWedamulla que es específico de su código entonces. Sin embargo
Günter Zöchbauer
1
¿No necesita darse de baja de esto también o se hace automáticamente?
rain01
1
@ rain01 como regla general, debe darse de baja explícitamente en su cpde cuando se suscribió explícitamente. Si tiene el código anterior en su componente raíz, cancelar la suscripción es redundante porque la vida útil del componente raíz suele ser la misma que la de toda la aplicación Angular.
Günter Zöchbauer
103

Puede ajustar la estrategia de reutilización en el enrutador.

constructor(private router: Router) {
    // override the route reuse strategy
    this.router.routeReuseStrategy.shouldReuseRoute = function() {
        return false;
    };
}
Pascal
fuente
2
Esto iniciará el ngInit de cada componente de la página.
jforjs
2
Bueno, @Pascal, me obligaste a iniciar sesión en SO solo para votar tu respuesta. Yo añadiría que en angular 6 también debe agregar onSameUrlNavigation: 'reload'al objeto de configuración de este modo: RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'}). Sin embargo, no puedo hablar de ninguna otra versión de Angular.
Hildy
1
@Hildy, me vi obligado a hacer lo mismo :) ¡Gracias @Pascal! si prefiere lambda puede hacer esto this.router.routeReuseStrategy.shouldReuseRoute = () => false;
nick
1
@Swaprks creé un routing.module.ts y coloqué el código como este constructor
Pascal
1
@Swaprks .. Tengo un problema similar y me gustaría probar su respuesta anterior. Pero no me dice mucho como principiante en este campo. ¿Exactamente en qué parte del código se supone que debo colocar esta pieza de código? ¿Se supone que debo cambiar algo en el fragmento de código (por ejemplo, ´function () ´)? Si creó un nuevo archivo con el nombre routing.module.ts, ¿cómo se supone que interactuará con otros archivos entonces? También hay un archivo llamado app-routing.module.ts que se crea automáticamente.
edn
21

Angular 9

He usado lo siguiente y funcionó.

onButtonClick() {
    this.router.routeReuseStrategy.shouldReuseRoute = function () {
        return false;
    }
    this.router.onSameUrlNavigation = 'reload';
    this.router.navigate('/myroute', { queryParams: { index: 1 } });
}
Guru Cse
fuente
1
Además, también use lambda en lugar de arriba, this.router.routeReuseStrategy.shouldReuseRoute = () => false;
Dhwanil Patel
Funciona en Angular 8.
Kishan Vaishnav
2
¿Cambiaría esto el comportamiento del enrutador en toda la aplicación o solo se activará una vez para este específico navigate()?
Halfist
8

¿Probablemente necesita volver a cargar la página? Esta es mi solución: he cambiado el @NgModule (en el archivo app-routing.module.ts en mi caso):

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})] })
Dionis Oros
fuente
¿Cuáles son las 'rutas' aquí.
Dhwanil Patel
@DhwanilPatel sus rutas de aplicación Angular. Por ejemplo, "rutas constantes: Routes = [{ruta: 'centro de crisis', componente: CrisisListComponent}, {ruta: 'héroes', componente: HeroListComponent},]" angular.io/guide/router#register-router-and -Rutas
Dionis Oros
1

NgOnInitse llamaría una vez cuando se crea una instancia. Para la misma instancia NgOnInitno se volverá a llamar. Para llamarlo es necesario destruir la instancia creada.

micronyks
fuente
1

En su método de navegación,

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

Tuve el mismo problema, además recibí la advertencia:

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

Este sitio proporcionó la mejor solución:

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]));
  }
XnyXno
fuente
Con respecto a esto, deseo saber cómo manejar el problema cuando simplemente actualice la página con la nueva ruta. En ese caso, la advertencia NgZone seguirá estando presente.
Siddhant
0

Es probable que este problema se deba al hecho de que no está cancelando sus suscripciones usando ngOnDestroy. A continuación se explica cómo terminar.

  1. Traiga la siguiente importación de suscripción rxjs. import { Subscription } from 'rxjs/Subscription';

  2. Agregue OnDestory a su importación de Angular Core. import { Component, OnDestroy, OnInit } from '@angular/core';

  3. Agregue OnDestory a su clase de exportación. export class DisplayComponent implements OnInit, OnDestroy {

  4. Cree una propiedad de objeto con un valor de Suscripción de rxjs en su clase de exportación para cada suscripción en el componente. myVariable: Subscription;

  5. Establezca el valor de su suscripción a MyVariable: Subscriptions. this.myVariable = this.rmanagerService.getRPDoc(books[i].books.id).subscribe(value => {});

  6. Luego, justo debajo de ngOninit, coloque el enlace del ciclo de vida de ngOnDestory () e ingrese su declaración de cancelación de suscripción para su suscripción. Si tiene varios, agregue más ngOnDestroy() { this.myVariable.unsubscribe(); }

Steve Klock
fuente
Sigo escribiendo ngOnDestoryen ngOnDestroymi lugar también ;-)
Simon_Weaver
0

Cree una ruta diferente para el mismo componente en la matriz de rutas.

rutas const: Rutas = [{ruta: "aplicación", componente: MiComponente}, {ruta: "recarga de la aplicación", componente: MiComponente}];

Si la URL actual es "aplicación", navegue usando "recargar aplicación" y viceversa.

SA
fuente
0

Aquí hay una colección de las mejores ideas en esta página con más información.

Solución 1 - Utilice la suscripción de params:

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

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

En cada uno de sus componentes de enrutamiento que usan variables param, se incluyen lo siguiente:

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

Algunos problemas comunes con este código es que las suscripciones son asincrónicas y pueden ser más difíciles de manejar. Además, no puede olvidarse de darse de baja en ngOnDestroy o pueden suceder cosas malas.

Lo bueno es que esta es la forma más documentada y común de manejar este problema. También hay una mejora del rendimiento al hacerlo de esta manera, ya que está reutilizando la plantilla en lugar de destruirla y recrearla cada vez que visita una página.

Solución 2 - shouldReuseRoute / onSameUrlNavigation:

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

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

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

Encuentre dónde RouterModule.forRootse encuentra en su proyecto (normalmente se encuentra en app-routing.module.ts o app.module.ts):

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

// ...

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

Luego, en AppComponent agregue lo siguiente:

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

        // ...
    }

    // ...
}

Por último, en sus componentes de enrutamiento ahora puede manejar variables de parámetros como esta:

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;

        // ...
    }

    // ...
}

Los problemas comunes con esta solución es que no es común. Además, está cambiando el comportamiento predeterminado del marco angular, por lo que puede encontrarse con problemas con los que la gente normalmente no se encontraría.

Lo bueno es que todo su código es sincrónico y más fácil de entender.

Mark Thompson
fuente
-1

Considere mover el código que tenía en ngOnInit a ngAfterViewInit. Este último parece ser llamado en la navegación del enrutador y debería ayudarlo en este caso.

Manoj Amalraj
fuente
3
eso realmente no sucede
nadav
-7

Cuando desea navegar en el enrutador en la misma página y desea llamar a ngOnInit (), entonces lo hace así, por ejemplo,

this.router.navigate (['categoría / lista', categoría]). then (() => window.location.reload ());

Deepak Mali
fuente