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

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


person Jeeten Parmar    schedule 16.01.2017    source источник


Ответы (12)


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

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

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

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

person Günter Zöchbauer    schedule 16.01.2017
comment
эта подписка не работает, она сработает только при инициализации - person Osanda Wedamulla; 05.03.2019
comment
@OsandaWedamulla, которая специфична для вашего кода. Трудно сказать без более подробной информации. - person Günter Zöchbauer; 05.03.2019
comment
Разве вам не нужно отказываться от подписки или это делается автоматически? - person rain01; 14.06.2019
comment
@ rain01 как правило, вы должны явно отказаться от подписки в своем cpde, если вы явно подписались. Если у вас есть вышеуказанный код в корневом компоненте, то отказ от подписки является избыточным, потому что время жизни корневого компонента обычно такое же, как время жизни всего приложения Angular. - person Günter Zöchbauer; 14.06.2019
comment
Это решение работает в сочетании с stackoverflow.com/a/47827668/5284473 (или глобальной настройкой onSameUrlNavigation). - person S. Roose; 02.12.2020
comment
@ S.Roose это не для меня .. :( - person Raphael St; 05.12.2020

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

constructor(private router: Router) {
    // override the route reuse strategy
    this.router.routeReuseStrategy.shouldReuseRoute = function() {
        return false;
    };
}
person Pascal    schedule 15.12.2017
comment
Это инициирует ngInit каждого компонента на странице. - person jforjs; 04.06.2018
comment
@Pascal Awesome - person Abhay Singh; 13.07.2018
comment
Что ж, @Pascal, вы заставили меня войти в SO, чтобы проголосовать за ваш ответ. Я бы добавил, что в Angular 6 вы также должны добавить onSameUrlNavigation: 'reload' к объекту конфигурации следующим образом: RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'}). Однако я не говорю о каких-либо других версиях Angular. - person Hildy; 19.09.2018
comment
@Hildy, я был вынужден сделать то же самое :) Спасибо @Pascal! если вы предпочитаете лямбду, вы можете сделать это this.router.routeReuseStrategy.shouldReuseRoute = () = ›false; - person nick; 19.10.2018
comment
@Pascal где мне добавить эту запись? - person Swaprks; 02.12.2018
comment
@Swaprks я создал routing.module.ts и поместил код в качестве этого конструктора - person Pascal; 03.12.2018
comment
возможно, это должен быть принятый ответ; размещение элементов ngOnInit в подписке интуитивно не интуитивно - person Nylon Smile; 07.06.2019
comment
@Swaprks .. У меня аналогичная проблема, и я хотел бы попробовать ваш ответ выше. Но это мало что говорит мне, как новичку в этой области. Где именно в коде я должен разместить этот фрагмент кода? Могу ли я что-нибудь изменить во фрагменте кода (например, ´function () ´)? Если вы создали новый файл с именем routing.module.ts, как тогда он должен взаимодействовать с другими файлами? Также существует файл app-routing.module.ts, который создается автоматически. - person edn; 09.10.2019
comment
чувак, ты мой спасатель - person Raj; 13.10.2019
comment
все еще полезно ... Я попытался вызвать ngOnIt в angular 8 после навигации и не смог вызвать то же самое. после использования этого я теперь могу вызывать ngOnIt. не уверен, правильный ли это подход в angular 8 или нет, НО на данный момент он решает мою проблему. +1 за это. - person patel.milanb; 19.05.2020
comment
В моем случае это сработало. В моем случае у меня есть URL: / home / student / 1, в котором есть компонент, показывающий информацию об этом конкретном студенте с Id = 1 и ниже 2-го компонента, который имеет сетевой граф со всеми его братьями и сестрами. На панели навигации есть строка поиска, я ищу другого студента (скажем, студента с ID = 2). Используя предложенное выше решение, я заставляю создать весь компонент (поведение которого я хочу) и показываю мне все о студенте с ID = 2. - person hamza saber; 13.07.2020
comment
@ Pascal, Большое спасибо за ваш ответ. Он также дал мне правильный ответ, который я ищу. - person sawyinwaimon; 13.11.2020
comment
Меня сбивает с толку то, что /user/3 и /user/5 рассматриваются как равные. Но может я что-то не так понял. - person Chuck; 22.02.2021

Угловой 9

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

onButtonClick() {
    this.router.routeReuseStrategy.shouldReuseRoute = function () {
        return false;
    }
    this.router.onSameUrlNavigation = 'reload';
    this.router.navigate('/myroute', { queryParams: { index: 1 } });
}
person Guru Cse    schedule 05.05.2020
comment
Кроме того, также используйте лямбда вместо вышеуказанного this.router.routeReuseStrategy.shouldReuseRoute = () = ›false; - person Dhwanil Patel; 26.05.2020
comment
Работает в Angular 8. - person Kishan Vaishnav; 15.06.2020
comment
Изменит ли это поведение маршрутизатора в приложении или сработает только один раз для этого конкретного navigate()? - person Halfist; 18.08.2020
comment
Работает в Angular 9. - person Ilija Iličić; 25.11.2020
comment
@Halfist Я заметил, что после установки shouldReuseRoute он устанавливается для всего приложения. Я проверил это с помощью console.log (this.router.routeReuseStrategy на странице 1, установив стратегию для этой функции на странице 2, а затем вернувшись на страницу 1. При начальной загрузке страница 1 сообщает об отсутствии функции, но после перехода на страницу 2 и обратно, функция все еще существует.Если вы хотите использовать это только в 1 компоненте, возможно, переустановите стратегию в NgOnDestroy? - person S. ten Brinke; 08.07.2021

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

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})] })
person Dionis Oros    schedule 26.09.2018
comment
Какие здесь «маршруты». - person Dhwanil Patel; 26.05.2020
comment
@DhwanilPatel маршруты ваших приложений Angular. Например, const routes: Routes = [{path: 'cris-center', component: CrisisListComponent}, {path: 'heroes', component: HeroListComponent},] angular.io/guide/router#register-router-and-routes - person Dionis Oros; 03.06.2020

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

Решение 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, чтобы вы могли столкнуться с проблемами, с которыми обычно не сталкивались бы люди.

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

person Mark Thompson    schedule 10.04.2020
comment
Да, это сработало для меня, большое спасибо - person Orlando Alfonso; 29.01.2021

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

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

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

person micronyks    schedule 16.01.2017

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

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]));
  }
person XnyXno    schedule 09.07.2020
comment
В связи с этим я хочу знать, как справиться с проблемой, когда вы просто обновляете страницу с новым маршрутом. В этом случае предупреждение NgZone все равно будет присутствовать. - person Siddhant; 15.09.2020

Эта проблема, вероятно, возникает из-за того, что вы не прекращаете свои подписки с помощью 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. Создайте свойство объекта со значением «Подписка из rxjs» в своем классе экспорта для каждой подписки на компонент. myVariable: Subscription;

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

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

person Steve Klock    schedule 13.05.2018
comment
Я тоже продолжаю набирать ngOnDestory вместо ngOnDestroy ;-) - person Simon_Weaver; 22.02.2019

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

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

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

person S A    schedule 28.11.2019

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

person Manoj Amalraj    schedule 15.03.2017
comment
этого на самом деле не бывает - person nadav; 17.06.2017

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

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

person Deepak Mali    schedule 04.04.2019