Router Navigate ไม่เรียก ngOnInit เมื่ออยู่ในหน้าเดียวกัน


89

ฉันกำลังเรียกใช้router.navigateในหน้าเดียวกันพร้อมกับพารามิเตอร์สตริงการค้นหา ในกรณีngOnInit()นี้ไม่โทร. เป็นค่าเริ่มต้นหรือต้องเพิ่มอะไรอีก?

คำตอบ:


139

คุณสามารถฉีด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 ที่เฉพาะเจาะจงสำหรับรหัสของคุณแล้ว ยากที่จะบอกหากไม่มีรายละเอียดเพิ่มเติม
GünterZöchbauer

1
คุณไม่จำเป็นต้องยกเลิกการสมัครหรือทำโดยอัตโนมัติ?
ฝน

1
@ rain01 ตามหลักทั่วไปคุณควรยกเลิกการสมัครใน cpde ของคุณอย่างชัดเจนเมื่อคุณสมัครรับข้อมูลอย่างชัดเจน หากคุณมีโค้ดด้านบนในองค์ประกอบรากของคุณการยกเลิกการสมัครจะซ้ำซ้อนเนื่องจากอายุการใช้งานของส่วนประกอบรากมักจะเท่ากับอายุการใช้งานของแอป Angular ทั้งหมด
GünterZöchbauer

โซลูชันนี้ใช้งานได้เมื่อรวมกับstackoverflow.com/a/47827668/5284473 (หรือการตั้งค่า onSameUrlNavigation ทั่วโลก)
S. Roose

105

คุณสามารถปรับ reuseStrategy บนเราเตอร์ได้

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

2
สิ่งนี้จะเริ่มต้น ngInit ของทุกองค์ประกอบในหน้า
jforjs

3
อืม @Pascal คุณบังคับให้ฉันล็อกอินเข้าสู่ SO เพื่อโหวตคำตอบของคุณ ฉันจะเพิ่มว่าในเชิงมุม 6 คุณยังต้องเพิ่มไปยังวัตถุการตั้งค่าเพื่อต้องการ:onSameUrlNavigation: 'reload' RouterModule.forRoot(appRoutes, {onSameUrlNavigation: 'reload'})Coud ไม่ได้พูดถึง Angular เวอร์ชันอื่น ๆ
Hildy

1
@Hildy ฉันถูกบังคับให้ทำเช่นเดียวกัน :) ขอบคุณ @Pascal! หากคุณต้องการแลมบ์ดาคุณสามารถทำสิ่งนี้ได้
ชื่อเล่น

1
@Swaprks ฉันสร้าง Routing.module.ts และวางโค้ดเป็นตัวสร้างนี้
Pascal

2
@Swaprks .. ฉันมีปัญหาที่คล้ายกันและอยากจะลองดูคำตอบของคุณด้านบน แต่มันไม่ได้บอกอะไรฉันมากนักในฐานะผู้เริ่มต้นในสาขานี้ ฉันควรวางโค้ดชิ้นนี้ไว้ตรงไหนกันแน่ ฉันควรจะเปลี่ยนแปลงอะไรในข้อมูลโค้ดหรือไม่ (เช่น´function ()?) หากคุณสร้างไฟล์ใหม่โดยใช้ชื่อ Routing.module.ts มันควรจะโต้ตอบกับไฟล์อื่นอย่างไร? นอกจากนี้ยังมีไฟล์ชื่อ app-Routing.module.ts ซึ่งสร้างขึ้นโดยอัตโนมัติ
edn

24

เชิงมุม 9

ฉันใช้สิ่งต่อไปนี้และได้ผล

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

1
นอกจากนี้ยังใช้ lambda แทนข้างบน this.router.routeReuseStrategy.shouldReuseRoute = () => false;
Dhwanil Patel

ทำงานใน Angular 8
Kishan Vaishnav

3
สิ่งนี้จะเปลี่ยนพฤติกรรมของเราเตอร์ทั่วทั้งแอปพลิเคชันหรือเรียกใช้เพียงครั้งเดียวสำหรับสิ่งนี้navigate()?
Halfist

ทำงานใน Angular 9.
Ilija Iličić

9

คุณอาจต้องโหลดหน้าใหม่หรือไม่? นี่คือวิธีแก้ปัญหาของฉัน: ฉันได้เปลี่ยน@NgModule (ในไฟล์app-routeing.module.tsในกรณีของฉัน):

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

'เส้นทาง' ตรงนี้คืออะไร
Dhwanil Patel

@DhwanilPatel เส้นทางแอพเชิงมุมของคุณ ตัวอย่างเช่น "const route: Routes = [{path: 'crisis-center', component: CrisisListComponent}, {path: 'heroes', component: HeroListComponent},]" angular.io/guide/router#register-router-and
Dionis Oros

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 จะยังคงปรากฏอยู่
Siddhant

0

ปัญหานี้น่าจะมาจากข้อเท็จจริงที่ว่าคุณไม่ได้ยกเลิกการสมัครสมาชิกโดยใช้ ngOnDestroy นี่คือวิธีที่จะทำให้เสร็จ

  1. นำเข้าการสมัครสมาชิก rxjs ต่อไปนี้ import { Subscription } from 'rxjs/Subscription';

  2. เพิ่ม OnDestory ในการนำเข้า Angular Core ของคุณ import { Component, OnDestroy, OnInit } from '@angular/core';

  3. เพิ่ม OnDestory ในคลาสส่งออกของคุณ export class DisplayComponent implements OnInit, OnDestroy {

  4. สร้างคุณสมบัติอ็อบเจ็กต์ที่มีค่า Subscription จาก 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

สร้างเส้นทางอื่นสำหรับส่วนประกอบเดียวกันในอาร์เรย์เส้นทาง

เส้นทาง const: Routes = [{path: "app", component: MyComponent}, {path: "app-reload", component: MyComponent}];

หาก URL ปัจจุบันคือ "app" ให้นำทางโดยใช้ "app-reload" และในทางกลับกัน


0

นี่คือชุดของแนวคิดที่ดีที่สุดในหน้านี้พร้อมข้อมูลเพิ่มเติม

โซลูชันที่ 1 - ใช้การสมัครสมาชิก params:

บทช่วยสอน: https://angular-2-training-book.rangle.io/routing/routeparams#reading-route-parameters

เอกสาร: https://angular.io/api/router/ActivatedRoute#params

ในแต่ละองค์ประกอบการกำหนดเส้นทางของคุณที่ใช้ตัวแปรพารามีดังต่อไปนี้:

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;

        // ...
    }

    // ...
}

ปัญหาทั่วไปในการแก้ปัญหานี้ไม่ใช่เรื่องธรรมดา นอกจากนี้คุณกำลังเปลี่ยนพฤติกรรมเริ่มต้นของเฟรมเวิร์กเชิงมุมดังนั้นคุณสามารถพบปัญหาที่คนทั่วไปไม่เคยพบเจอ

สิ่งที่ดีคือรหัสทั้งหมดของคุณซิงโครนัสและเข้าใจง่ายขึ้น


-1

ลองย้ายโค้ดที่คุณมีใน ngOnInit ไปที่ ngAfterViewInit อย่างหลังดูเหมือนจะถูกเรียกในการนำทางของเราเตอร์และควรช่วยคุณในกรณีนี้


3
ที่ไม่ได้เกิดขึ้นจริง
nadav

-7

เมื่อคุณต้องการให้เราเตอร์ไปที่หน้าเดียวกันและต้องการเรียกใช้ ngOnInit () คุณจึงทำเช่นนั้นเช่น

this.router.navigate (['หมวดหมู่ / รายการ', หมวดหมู่]). แล้ว (() => window.location.reload ());

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.