Router Navigate nie wywołuje ngOnInit, gdy ta sama strona


86

Wzywam router.navigatena tej samej stronie z niektórymi parametrami ciągu zapytania. W tym przypadku ngOnInit()nie dzwoni. Czy jest to ustawienie domyślne, czy muszę dodać coś jeszcze?

Odpowiedzi:


136

Możesz wstrzyknąć ActivatedRoutei subskrybowaćparams

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

Router niszczy i odtwarza komponent tylko wtedy, gdy przechodzi do innej trasy. Gdy aktualizowane są tylko parametry trasy lub parametry zapytania, ale trasa jest taka sama, komponent nie zostanie zniszczony i odtworzony.

Alternatywnym sposobem wymuszenia ponownego utworzenia komponentu jest użycie niestandardowej strategii ponownego wykorzystania. Zobacz też Angular2 router 2.0.0 nie przeładowuje komponentów, gdy ten sam adres URL jest ładowany z różnymi parametrami? (wydaje się, że nie ma jeszcze wielu dostępnych informacji, jak to wdrożyć)


1
ta subskrypcja nie działa, uruchomi się tylko po uruchomieniu
Osanda Wedamulla

@OsandaWedamulla jest specyficzne dla twojego kodu. Trudno jednak powiedzieć bez więcej szczegółów
Günter Zöchbauer

1
Czy nie musisz również rezygnować z subskrypcji, czy też odbywa się to automatycznie?
deszcz 01

1
@ rain01 Zasadniczo powinieneś wyraźnie anulować subskrypcję w swoim CPDE, jeśli wyraźnie subskrybujesz. Jeśli masz powyższy kod w swoim głównym składniku, anulowanie subskrypcji jest zbędne, ponieważ czas życia składnika głównego jest zwykle taki sam, jak czas życia całej aplikacji Angular.
Günter Zöchbauer

103

Możesz dostosować strategię reuseStrategy na routerze.

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

2
Spowoduje to zainicjowanie ngInit każdego komponentu na stronie.
jforjs

2
Cóż, @Pascal, zmusiłeś mnie do zalogowania się do SO tylko po to, aby zagłosować za Twoją odpowiedź. Dodam, że w kątowych 6 należy również dodać onSameUrlNavigation: 'reload'do obiektu config tak: RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'}). Nie mogę jednak mówić o innych wersjach Angulara.
Hildy

1
@Hildy, byłem zmuszony zrobić to samo :) Dzięki @Pascal! jeśli wolisz lambdę, możesz to zrobić. router.routeReuseStrategy.shouldReuseRoute = () => false;
nick

1
@Swaprks Utworzyłem routing.module.ts i umieściłem kod jako ten konstruktor
Pascal

1
@Swaprks .. Mam podobny problem i chciałbym wypróbować Twoją odpowiedź powyżej. Ale to nie mówi mi wiele jako początkującego w tej dziedzinie. Dokładnie gdzie w kodzie mam umieścić ten fragment kodu? Czy mam coś zmienić we fragmencie kodu (np. „Function ()”)? Jeśli utworzyłeś nowy plik o nazwie routing.module.ts, w jaki sposób powinien on współdziałać z innymi plikami? Istnieje również plik o nazwie app-routing.module.ts, który jest tworzony automatycznie.
edn

21

Kątowy 9

Użyłem następujących i zadziałało.

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

1
Ponadto zamiast powyższego użyj również wyrażenia lambda, this.router.routeReuseStrategy.shouldReuseRoute = () => false;
Dhwanil Patel

Działa w Angular 8.
Kishan Vaishnav

2
Czy zmieniłoby to zachowanie routera w całej aplikacji, czy tylko uruchomiłoby się tylko raz dla tego konkretnego navigate()?
Halfist

8

Czy prawdopodobnie potrzebujesz przeładować stronę? Oto moje rozwiązanie: zmieniłem @NgModule (w pliku app-routing.module.ts w moim przypadku):

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

Jakie są tutaj „trasy”.
Dhwanil Patel

@DhwanilPatel swoje trasy aplikacji Angular. Na przykład „const Routes: Routes = [{ścieżka: 'kryzys-centrum', komponent: CrisisListComponent}, {path: 'heroes', component: HeroListComponent},]" angular.io/guide/router#register-router-and -trasy
Dionis Oros

1

NgOnInitbyłaby wywoływana raz podczas tworzenia instancji. W tym samym przypadku NgOnInitnie zostanie ponownie wywołany. Aby to wywołać, konieczne jest zniszczenie utworzonej instancji.


1

W Twojej metodzie nawigacji

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

1

Miałem ten sam problem, dodatkowo dostałem ostrzeżenie:

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

Ta witryna zapewniła najlepsze rozwiązanie:

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

W związku z tym chciałbym wiedzieć, jak rozwiązać ten problem, gdy po prostu odświeżysz stronę nową trasą. W takim przypadku ostrzeżenie NgZone będzie nadal obecne.
Siddhant

0

Ten problem prawdopodobnie wynika z faktu, że nie przerywasz subskrypcji za pomocą ngOnDestroy. Oto jak to zrobić.

  1. Wprowadź następujący import subskrypcji rxjs. import { Subscription } from 'rxjs/Subscription';

  2. Dodaj OnDestory do swojego importu Angular Core. import { Component, OnDestroy, OnInit } from '@angular/core';

  3. Dodaj OnDestory do swojej klasy eksportu. export class DisplayComponent implements OnInit, OnDestroy {

  4. Utwórz właściwość obiektu o wartości Subskrypcja z rxjs w ramach klasy eksportu dla każdej subskrypcji składnika. myVariable: Subscription;

  5. Ustaw wartość swojej subskrypcji na MyVariable: Subscriptions. this.myVariable = this.rmanagerService.getRPDoc(books[i].books.id).subscribe(value => {});

  6. Następnie tuż pod ngOninit umieść haczyk cyklu życia ngOnDestory () i umieść oświadczenie o rezygnacji z subskrypcji dla subskrypcji. Jeśli masz wiele, dodaj więcej ngOnDestroy() { this.myVariable.unsubscribe(); }


Ja też piszę ngOnDestoryzamiast ngOnDestroysiebie ;-)
Simon_Weaver,

0

Utwórz inną ścieżkę dla tego samego komponentu w tablicy tras.

const routes: Routes = [{ścieżka: "aplikacja", komponent: MyComponent}, {ścieżka: "app-reload", komponent: MyComponent}];

Jeśli aktualny adres URL to „aplikacja”, użyj opcji „przeładowanie aplikacji” i odwrotnie.


0

Oto zbiór najlepszych pomysłów na tej stronie wraz z dodatkowymi informacjami

Rozwiązanie 1 - Użyj subskrypcji params:

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

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

W każdym z komponentów routingu, które używają zmiennych param, znajdują się następujące elementy:

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

Niektóre typowe problemy z tym kodem polegają na tym, że subskrypcje są asynchroniczne i mogą być trudniejsze do rozwiązania. Nie możesz też zapomnieć o anulowaniu subskrypcji na ngOnDestroy, bo inaczej mogą się zdarzyć złe rzeczy.

Dobrze, że jest to najbardziej udokumentowany i powszechny sposób rozwiązania tego problemu. W ten sposób można również poprawić wydajność, ponieważ ponownie używasz szablonu zamiast niszczyć i odtwarzać za każdym razem, gdy odwiedzasz stronę.

Rozwiązanie 2 - shouldReuseRoute / onSameUrlNavigation:

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

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

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

Znajdź RouterModule.forRootlokalizację w projekcie (zwykle w app-routing.module.ts lub app.module.ts):

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

// ...

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

Następnie w AppComponent dodaj następujące elementy:

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

        // ...
    }

    // ...
}

Wreszcie, w komponentach routingu możesz teraz obsługiwać zmienne param w następujący sposób:

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;

        // ...
    }

    // ...
}

Typowe problemy z tym rozwiązaniem polegają na tym, że nie jest powszechne. Zmieniasz również domyślne zachowanie frameworka Angular, dzięki czemu możesz napotkać problemy, na które normalnie nie napotkaliby ludzie.

Dobrze, że cały twój kod jest synchroniczny i łatwiejszy do zrozumienia.


-1

Rozważ przeniesienie kodu z ngOnInit do ngAfterViewInit. Ten ostatni wydaje się być wywoływany w nawigacji routera i powinien pomóc w tym przypadku.


3
to się nie zdarza
nadav

-7

Jeśli chcesz, aby router nawigował po tej samej stronie i chcesz wywołać ngOnInit (), robisz to, np.

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.