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

SA
источник
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 ());

Дипак Мали
источник