Router Navigate не вызывает ngOnInit, когда та же страница


86

Я звоню router.navigateна ту же страницу с некоторыми параметрами строки запроса. В этом случае ngOnInit()не звонит. Это по умолчанию или мне нужно что-то еще добавить?

Ответы:


136

Вы можете ввести ActivatedRouteи подписаться наparams

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

Маршрутизатор уничтожает и воссоздает компонент только тогда, когда он переходит на другой маршрут. Когда обновляются только параметры маршрута или параметры запроса, но маршрут остается таким же, компонент не будет уничтожен и воссоздан.

Альтернативный способ принудительного воссоздания компонента - использовать настраиваемую стратегию повторного использования. См. Также Angular2 router 2.0.0, который не перезагружает компоненты, когда один и тот же URL-адрес загружен с разными параметрами? (похоже, пока не так много информации о том, как это реализовать)


1
эта подписка не работает, она активируется только при инициализации
— Осанда Ведамулла

@OsandaWedamulla, которая специфична для вашего кода. Трудно сказать без более подробной информации
— Günter Zöchbauer

1
Разве вам не нужно отказываться от подписки или это делается автоматически?
— rain01

1
@ rain01 как правило, вы должны явно отказаться от подписки в своем cpde, когда вы явно подписались. Если у вас есть вышеуказанный код в корневом компоненте, то отказ от подписки является избыточным, потому что время жизни корневого компонента обычно такое же, как время жизни всего приложения Angular.
— Günter Zöchbauer

103

Вы можете настроить reuseStrategy на маршрутизаторе.

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

2
Это инициирует ngInit каждого компонента на странице.
— jforjs 04

2
Что ж, @Pascal, вы заставили меня войти в SO, чтобы проголосовать за ваш ответ. Я хотел бы добавить , что в угловых 6 Вы должны также добавить onSameUrlNavigation: 'reload'к объекту конфигурации следующим образом: RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'}). Однако я не говорю о каких-либо других версиях Angular.
— Hildy

1
@Hildy, я был вынужден сделать то же самое :) Спасибо @Pascal! если вы предпочитаете лямбду, вы можете сделать это this.router.routeReuseStrategy.shouldReuseRoute = () => false;
— Ник

1
@Swaprks Я создал routing.module.ts и поместил код в качестве этого конструктора
— Паскаль

1
@Swaprks .. У меня аналогичная проблема, и я хотел бы попробовать ваш ответ выше. Но это мало что говорит мне, как новичку в этой области. Где именно в коде я должен разместить этот фрагмент кода? Должен ли я что-то изменить во фрагменте кода (например, «function ()»)? Если вы создали новый файл с именем routing.module.ts, как тогда он должен взаимодействовать с другими файлами? Также существует файл app-routing.module.ts, который создается автоматически.
— edn

21

Угловой 9

Я использовал следующее, и это сработало.

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

1
Кроме того, также используйте лямбда вместо вышеуказанного this.router.routeReuseStrategy.shouldReuseRoute = () => false;
— Дхванил Патель,

Работает в Angular 8.
— Кишан Вайшнав

2
Изменит ли это поведение маршрутизатора в приложении или сработает только один раз для этого конкретного navigate()?
— Halfist

8

Возможно, вам нужна перезагрузка страницы? Это мое решение: я изменил @NgModule ( в моем случае в файле app-routing.module.ts ):

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

Какие здесь «маршруты».
— Дхванил Патель,

@DhwanilPatel маршруты ваших приложений Angular. Например, "const routes: Routes = [{путь: 'кризис-центр', компонент: CrisisListComponent}, {путь: 'герои', компонент: HeroListComponent},]" angular.io/guide/router#register-router-and -маршруты
— Дионис Орос

1

NgOnInitбудет вызываться один раз при создании экземпляра. Ибо тот же экземпляр NgOnInitбольше не будет вызван. Для его вызова необходимо уничтожить созданный экземпляр.


1

На вашем методе навигации,

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

1

У меня была такая же проблема, кроме того, я получил предупреждение:

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

Этот сайт предоставил лучшее решение:

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

В связи с этим я хочу знать, как справиться с проблемой, когда вы просто обновляете страницу новым маршрутом. В этом случае предупреждение NgZone по-прежнему будет присутствовать.
— Сиддхант

0

Эта проблема, вероятно, возникает из-за того, что вы не прекращаете подписку с помощью ngOnDestroy. Вот как это сделать.

  1. Принесите следующий импорт подписки rxjs. import { Subscription } from 'rxjs/Subscription';

  2. Добавьте OnDestory в свой Angular Core Import. import { Component, OnDestroy, OnInit } from '@angular/core';

  3. Добавьте OnDestory в свой экспортный класс. export class DisplayComponent implements OnInit, OnDestroy {

  4. Создайте свойство объекта со значением Subscription from rxjs в вашем классе экспорта для каждой подписки на компонент. myVariable: Subscription;

  5. Установите для своей подписки значение MyVariable: Subscriptions. this.myVariable = this.rmanagerService.getRPDoc(books[i].books.id).subscribe(value => {});

  6. Затем прямо под ngOninit поместите крючок жизненного цикла ngOnDestory () и вставьте оператор отказа от подписки для своей подписки. Если у вас их несколько, добавьте еще ngOnDestroy() { this.myVariable.unsubscribe(); }


Я тоже продолжаю печатать ngOnDestoryвместо ngOnDestroyсебя ;-)
— Simon_Weaver

0

Создайте другой путь для того же компонента в массиве маршрутов.

константные маршруты: Routes = [{путь: "приложение", компонент: MyComponent}, {путь: "приложение-перезагрузка", компонент: MyComponent}];

Если текущий URL-адрес - «app», используйте для навигации «app-reload» и наоборот.


0

Вот коллекция лучших идей на этой странице с дополнительной информацией

Решение 1. Используйте подписку на параметры:

Учебник: https://angular-2-training-book.rangle.io/routing/routeparams#reading-route-parameters

Документы: https://angular.io/api/router/ActivatedRoute#params

В каждом из ваших компонентов маршрутизации, которые используют переменные param, включают следующее:

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

Некоторые общие проблемы с этим кодом заключаются в том, что подписки являются асинхронными, и с ними может быть сложнее справиться. Также вы не можете забыть отказаться от подписки на ngOnDestroy, иначе могут случиться неприятности.

Хорошо, что это наиболее документированный и распространенный способ решения этой проблемы. Это также улучшает производительность, поскольку вы повторно используете шаблон вместо того, чтобы уничтожать и воссоздавать каждый раз, когда вы посещаете страницу.

Решение 2 - shouldReuseRoute / onSameUrlNavigation:

Документы: https://angular.io/api/router/ExtraOptions#onSameUrlNavigation

Документы: https://angular.io/api/router/RouteReuseStrategy#shouldReuseRoute

Документы: https://angular.io/api/router/ActivatedRouteSnapshot#params

Найдите, где RouterModule.forRootнаходится в вашем проекте (обычно находится в app-routing.module.ts или app.module.ts):

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

// ...

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

Затем в AppComponent добавьте следующее:

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

        // ...
    }

    // ...
}

Наконец, в ваших компонентах маршрутизации вы теперь можете обрабатывать переменные param следующим образом:

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;

        // ...
    }

    // ...
}

Распространенные проблемы с этим решением в том, что оно встречается редко. Также вы меняете поведение фреймворка Angular по умолчанию, чтобы вы могли столкнуться с проблемами, с которыми обычно не сталкивались бы люди.

Хорошо то, что весь ваш код синхронный и более понятный.


-1

Подумайте о переносе кода, который у вас был в ngOnInit, в ngAfterViewInit. Последний, похоже, вызывается при навигации по маршрутизатору и должен помочь вам в этом случае.


3
этого на самом деле не происходит
— nadav

-7

Если вы хотите, чтобы маршрутизатор перемещался на той же странице и хотите вызвать ngOnInit (), вам это нравится, например,

this.router.navigate (['категория / список', категория]) .then (() => window.location.reload ());

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.