O Router Navigate não chama ngOnInit na mesma página

86

Estou chamando router.navigatena mesma página com alguns parâmetros de string de consulta. Nesse caso, ngOnInit()não liga. É por padrão ou preciso adicionar mais alguma coisa?

Jeeten Parmar
fonte

Respostas:

136

Você pode injetar o ActivatedRoutee assinarparams

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

O roteador apenas destrói e recria o componente quando navega para uma rota diferente. Quando apenas parâmetros de rota ou parâmetros de consulta são atualizados, mas a rota é a mesma, o componente não será destruído e recriado.

Uma maneira alternativa de forçar o componente a ser recriado é usar uma estratégia de reutilização personalizada. Veja também Roteador Angular2 2.0.0 não recarregando componentes quando o mesmo url é carregado com parâmetros diferentes? (não parece haver muita informação disponível ainda como implementá-lo)

Günter Zöchbauer
fonte
1
esta assinatura não está funcionando, ela só
será ativada
@OsandaWedamulla que é específico para seu código então. É difícil dizer sem mais detalhes
Günter Zöchbauer
1
Você também não precisa cancelar a assinatura ou isso é feito automaticamente?
rain01
1
@ rain01 como regra geral, você deve cancelar explicitamente a inscrição em seu cpde ao se inscrever explicitamente. Se você tiver o código acima em seu componente raiz, o cancelamento da assinatura é redundante porque a vida útil do componente raiz é geralmente igual à vida útil de todo o aplicativo Angular.
Günter Zöchbauer
103

Você pode ajustar o reuseStrategy no Roteador.

constructor(private router: Router) {
    // override the route reuse strategy
    this.router.routeReuseStrategy.shouldReuseRoute = function() {
        return false;
    };
}
Pascal
fonte
2
Isso iniciará o ngInit de todos os componentes da página.
jforjs
2
Bem, @Pascal, você me obrigou a entrar no SO apenas para votar sua resposta. Gostaria de acrescentar que no Angular 6 você também deve adicionar onSameUrlNavigation: 'reload'ao objeto de configuração assim: RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'}). Não posso falar por nenhuma outra versão Angular, entretanto.
Hildy
1
@Hildy, fui compelido a fazer o mesmo :) Obrigado @Pascal! se preferir lambda, você pode fazer this.router.routeReuseStrategy.shouldReuseRoute = () => false;
nick
1
@Swaprks eu criei um routing.module.ts e coloquei o código como este construtor
Pascal
1
@Swaprks .. Tenho um problema semelhante e gostaria de tentar sua resposta acima. Mas isso não me diz muito para um iniciante neste campo. Exatamente onde no código devo colocar este trecho de código? Devo mudar alguma coisa no trecho de código (por exemplo, ´função () ´)? Se você criou um novo arquivo com o nome de routing.module.ts, como ele deve interagir com outros arquivos? Há também um arquivo chamado app-routing.module.ts que é criado automaticamente.
edn
21

Angular 9

Eu usei o seguinte e funcionou.

onButtonClick() {
    this.router.routeReuseStrategy.shouldReuseRoute = function () {
        return false;
    }
    this.router.onSameUrlNavigation = 'reload';
    this.router.navigate('/myroute', { queryParams: { index: 1 } });
}
Guru Cse
fonte
1
Além disso, também use lambda em vez de acima, this.router.routeReuseStrategy.shouldReuseRoute = () => false;
Dhwanil Patel
Trabalha em Angular 8.
Kishan Vaishnav
2
Isso mudaria o comportamento do roteador no aplicativo ou apenas acionaria uma vez para este específico navigate()?
Halfist
8

Você provavelmente precisa recarregar a página? Esta é a minha solução: mudei o @NgModule (no arquivo app-routing.module.ts no meu caso):

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})] })
Dionis Oros
fonte
Quais são as 'rotas' por aqui.
Dhwanil Patel
@DhwanilPatel suas rotas de aplicativos Angular. Por exemplo "const routes: Routes = [{path: 'crisis-center', component: CrisisListComponent}, {path: 'heroes', component: HeroListComponent},]" angular.io/guide/router#register-router-and -rotas
Dionis Oros
1

NgOnInitseria chamado uma vez quando uma instância for criada. Pois a mesma instância NgOnInitnão será chamada novamente. Para chamá-lo é necessário destruir a instância criada.

micronyks
fonte
1

No seu método de navegação,

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

Eu tive o mesmo problema, além disso, recebi o aviso:

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

Este site forneceu a melhor solução:

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
fonte
Com relação a isso, gostaria de saber como lidar com o problema quando você simplesmente atualiza a página com a nova rota. Nesse caso, o aviso NgZone ainda estará presente.
Siddhant
0

Esse problema provavelmente está vindo do fato de que você não está encerrando suas assinaturas usando ngOnDestroy. Aqui está como fazer.

  1. Traga a seguinte importação de assinatura rxjs. import { Subscription } from 'rxjs/Subscription';

  2. Adicione OnDestory à sua importação Angular Core. import { Component, OnDestroy, OnInit } from '@angular/core';

  3. Adicione OnDestory à sua classe de exportação. export class DisplayComponent implements OnInit, OnDestroy {

  4. Crie uma propriedade de objeto com um valor de Subscription from rxjs em sua classe de exportação para cada assinatura no componente. myVariable: Subscription;

  5. Defina o valor de sua assinatura para MyVariable: Subscriptions. this.myVariable = this.rmanagerService.getRPDoc(books[i].books.id).subscribe(value => {});

  6. Então, logo abaixo do ngOninit, coloque o gancho do ciclo de vida ngOnDestory () e coloque sua instrução de cancelamento de assinatura para sua assinatura. Se você tiver vários, adicione mais ngOnDestroy() { this.myVariable.unsubscribe(); }

Steve Klock
fonte
Eu continuo digitando em ngOnDestoryvez de ngOnDestroyeu também ;-)
Simon_Weaver
0

Crie um caminho diferente para o mesmo componente na matriz de rotas.

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

Se o URL atual for "app", navegue usando "app-reload" e vice-versa.

SA
fonte
0

Aqui está uma coleção das melhores ideias nesta página com mais informações

Solução 1 - Use a assinatura do params:

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

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

Em cada um dos seus componentes de roteamento que usam variáveis ​​param, incluem o seguinte:

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

Alguns problemas comuns com esse código são que as assinaturas são assíncronas e podem ser mais difíceis de lidar. Além disso, você não pode se esquecer de cancelar a assinatura do ngOnDestroy, ou coisas ruins podem acontecer.

O bom é que essa é a maneira mais documentada e comum de lidar com esse problema. Também há uma melhoria de desempenho ao fazer isso dessa maneira, já que você está reutilizando o modelo em vez de destruir e recriar cada vez que visitar uma página.

Solução 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

Encontre onde RouterModule.forRootestá localizado em seu projeto (normalmente encontrado em app-routing.module.ts ou app.module.ts):

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

// ...

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

Em seguida, em AppComponent, adicione o seguinte:

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, em seus componentes de roteamento, você agora pode lidar com variáveis ​​de parâmetros como este:

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;

        // ...
    }

    // ...
}

Os problemas comuns com essa solução é que ela não é comum. Além disso, você está alterando o comportamento padrão da estrutura Angular, para que possa enfrentar problemas que as pessoas normalmente não encontrariam.

O bom é que todo o seu código é síncrono e mais fácil de entender.

Mark Thompson
fonte
-1

Considere mover o código que você tinha em ngOnInit para ngAfterViewInit. Este último parece ser chamado na navegação do roteador e deve ajudá-lo neste caso.

Manoj Amalraj
fonte
3
isso realmente não acontece
nadav
-7

Quando você deseja navegar no roteador na mesma página e deseja chamar ngOnInit (), você faz assim, por exemplo,

this.router.navigate (['categoria / lista', categoria]) .então (() => window.location.reload ());

Deepak Mali
fonte