Router Navigate не викликає ngOnInit на одній сторінці


86

Я телефоную router.navigateна ту саму сторінку з деякими параметрами рядка запиту. У цьому випадку ngOnInit()не дзвонить. Це за замовчуванням чи мені потрібно додати ще щось?

Відповіді:


136

Ви можете зробити ін'єкцію ActivatedRouteта підписатися на неїparams

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

Маршрутизатор руйнує та відтворює компонент лише тоді, коли він переходить на інший маршрут. Коли оновлюються лише параметри маршруту або параметри запиту, але маршрут однаковий, компонент не буде знищений і відтворений.

Альтернативний спосіб примусити компонент до відтворення - використовувати власну стратегію повторного використання. Див. Також маршрутизатор Angular2 2.0.0, який не перезавантажує компоненти, коли однакова URL-адреса завантажена з різними параметрами? (схоже, поки що немає багато інформації, як її реалізувати)


1
ця підписка не працює, вона буде спрацьовувати лише на init
Osanda Wedamulla

@OsandaWedamulla, що є специфічним для вашого коду тоді. Важко сказати без більш детальних відомостей
Гюнтер Цьохбауер,

1
Вам не потрібно також скасувати підписку на це, чи це робиться автоматично?
rain01

1
@ rain01, як правило, вам слід явно скасувати підписку на ваш cpde, коли ви явно підписалися. Якщо у вашому кореневому компоненті є код вище, то скасування підписки зайве, оскільки час життя кореневого компонента, як правило, збігається з життям усієї програми Angular.
Гюнтер Цохбауер,

103

Ви можете налаштувати стратегію повторного використання на маршрутизаторі.

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

2
Це ініціює ngInit кожного компонента на сторінці.
jforjs

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

1
@Hildy, мене змусили зробити те саме :) Дякую @Pascal! якщо ви віддаєте перевагу лямбда, ви можете зробити це this.router.routeReuseStrategy.shouldReuseRoute = () => false;
нік

1
@Swaprks я створив routeing.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 = [{path: 'krize-center', component: CrisisListComponent}, {path: 'heroes', component: 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 до свого Імпорту кутового ядра. import { Component, OnDestroy, OnInit } from '@angular/core';

  3. Додайте OnDestory до свого класу експорту. export class DisplayComponent implements OnInit, OnDestroy {

  4. Створіть властивість об’єкта зі значенням Subscription з rxjs під вашим класом експорту для кожної підписки на компонент. myVariable: Subscription;

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

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


Я продовжую друкувати ngOnDestoryзамість ngOnDestroyсебе ;-)
Simon_Weaver

0

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

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

Якщо поточною URL-адресою є "додаток", перейдіть за допомогою "перезавантажити додаток" і навпаки.


0

Ось збірка найкращих ідей на цій сторінці з додатковою інформацією

Рішення 1 - Використовуйте підписку на params:

Підручник: 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;
        };

        // ...
    }

    // ...
}

Нарешті, у ваших компонентах маршрутизації ви тепер можете обробляти змінні параметра, як це:

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
цього насправді не буває
надав

-7

Коли ви хочете, щоб маршрутизатор переміщався по тій самій сторінці і хочете викликати ngOnInit (), то вам це подобається, наприклад,

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.