จะกำหนด URL ของหน้าก่อนหน้าใน Angular ได้อย่างไร?


99

สมมติว่าผมอยู่บนหน้าเว็บที่มี /user/:idURL :id/postsตอนนี้จากหน้านี้ฉันนำทางไปยังหน้าถัดไป

ตอนนี้มีวิธีใดบ้างที่ฉันสามารถตรวจสอบว่า URL ก่อนหน้าคือ/user/:idอะไรเช่น.

ด้านล่างนี้คือเส้นทางของฉัน

export const routes: Routes = [
  { 
    path: 'user/:id', component: UserProfileComponent
  },
  {  
    path: ':id/posts', component: UserPostsComponet 
  }
];

คำตอบ:


80

คุณสามารถสมัครรับการเปลี่ยนแปลงเส้นทางและจัดเก็บเหตุการณ์ปัจจุบันเพื่อให้คุณสามารถใช้งานได้เมื่อเกิดเหตุการณ์ต่อไป

previousUrl: string;
constructor(router: Router) {
  router.events
  .pipe(filter(event => event instanceof NavigationEnd))
  .subscribe((event: NavigationEnd) => {
    console.log('prev:', event.url);
    this.previousUrl = event.url;
  });
}

ดูวิธีตรวจจับการเปลี่ยนแปลงเส้นทางในเชิงมุม?


12
ขอบคุณ @ Günterคุณบันทึกวันของฉันไว้เสมอ
จันทราเชคาร์

29
นี่ไม่ได้แสดงรายการเส้นทางก่อนหน้าสำหรับฉัน แต่เป็นเส้นทางปัจจุบันเท่านั้น
David Aguirre

2
ขึ้นอยู่กับสิ่งที่คุณคาดหวัง ครั้งแรกเป็นnullเพราะไม่มีเส้นทางก่อนหน้านี้ คุณต้องทำสิ่งนี้บนเราเตอร์รูทมิฉะนั้นคุณจะได้รับก็ต่อเมื่อคุณนำทางระหว่างเส้นทางลูกของส่วนประกอบนี้
GünterZöchbauer

8
สิ่งนี้ไม่ได้ให้ url ก่อนหน้าเมื่อตัวสร้างถูกเรียกใช้งานเป็นครั้งแรก
Ekaitz Hernandez Troyas

9
คุณคาดหวังค่าใดเป็น url ก่อนหน้าเมื่อตัวสร้างถูกเรียกใช้งานเป็นครั้งแรก
GünterZöchbauer

108

บางทีคำตอบอื่น ๆ ทั้งหมดอาจใช้สำหรับเชิงมุม 2.X

ตอนนี้มันใช้ไม่ได้กับมุม 5.X. ฉันกำลังทำงานกับมัน

ด้วย NavigationEnd เท่านั้นคุณไม่สามารถรับ url ก่อนหน้านี้ได้

เนื่องจากเราเตอร์ทำงานจาก "NavigationStart", "RoutesRecognized", ... ถึง "NavigationEnd"

คุณสามารถตรวจสอบกับ

    router.events.forEach((event) => {
  console.log(event);
});

แต่คุณยังไม่สามารถรับ url ก่อนหน้าได้แม้จะมี "NavigationStart" ก็ตาม

ตอนนี้คุณต้องใช้คู่กัน

import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/pairwise';

constructor(private router: Router) {
  this.router.events
    .filter(e => e instanceof RoutesRecognized)
    .pairwise()
    .subscribe((event: any[]) => {
      console.log(event[0].urlAfterRedirects);
    });
}
    

ด้วยการจับคู่คุณสามารถดูว่า url มาจากอะไรและถึง

"RoutesRecognized" คือขั้นตอนการเปลี่ยนแปลงจากต้นทางเป็น URL เป้าหมาย

ดังนั้นกรองและรับ url ก่อนหน้าจากมัน

สุดท้าย แต่ไม่ท้ายสุด,

ใส่รหัสนี้ในองค์ประกอบหลักหรือสูงกว่า (เช่น app.component.ts)

เนื่องจากรหัสนี้เริ่มทำงานหลังจากเสร็จสิ้นการกำหนดเส้นทาง

อัปเดตเชิงมุม 6+

events.filterให้ข้อผิดพลาดเนื่องจากตัวกรองไม่เป็นส่วนหนึ่งของกิจกรรมเพื่อเปลี่ยนรหัสไป

import { filter, pairwise } from 'rxjs/operators';

this.router.events
.pipe(filter((evt: any) => evt instanceof RoutesRecognized), pairwise())
.subscribe((events: RoutesRecognized[]) => {
  console.log('previous url', events[0].urlAfterRedirects);
  console.log('current url', events[1].urlAfterRedirects);
});

2
นำไปใช้เป็นบริการและใช้งานได้ดี ฉันใช้เชิงมุม 6.1.7
A. El Idrissi

5
@ tjvg1991 การรีเฟรชหน้าหมายความว่าคุณสูญเสียข้อมูลหน่วยความจำ หากคุณเก็บข้อมูลก่อนหน้านี้คุณต้องใช้ localStorage หรือคุกกี้ (บันทึกข้อมูลในพื้นที่ของคุณไม่ใช่หน่วยความจำ)
BYUNGJU JIN

ฉันแค่อยากจะฆ่าปุ่ม Upvote ขอบคุณผู้ชาย
Muhammad Umair

@BYUNGJUJIN ขอบคุณสำหรับสิ่งนี้!
ห์น

@ BYUNGJU JIN ขอบคุณที่ทำงานให้ฉัน ฉันจะรับค่าของพารามิเตอร์จากลิงก์เปลี่ยนเส้นทางได้อย่างไรเช่นเหตุการณ์ [0] .urlAfterRedirects ให้ '/ InventoryDetails; test = 0; id = 45' ฉันต้องการรับค่าของ id จากสิ่งนี้ ฉันจะทำได้อย่างไรโดยไม่ต้องใช้ subString
JNPW

49

สร้างบริการฉีด:

import { Injectable } from '@angular/core';
import { Router, RouterEvent, NavigationEnd } from '@angular/router';

 /** A router wrapper, adding extra functions. */
@Injectable()
export class RouterExtService {

  private previousUrl: string = undefined;
  private currentUrl: string = undefined;

  constructor(private router : Router) {
    this.currentUrl = this.router.url;
    router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {        
        this.previousUrl = this.currentUrl;
        this.currentUrl = event.url;
      };
    });
  }

  public getPreviousUrl(){
    return this.previousUrl;
  }    
}

จากนั้นใช้งานได้ทุกที่ที่คุณต้องการ ในการจัดเก็บตัวแปรปัจจุบันโดยเร็วที่สุดจำเป็นต้องใช้บริการใน AppModule

// AppModule
export class AppModule {
  constructor(private routerExtService: RouterExtService){}

  //...

}

// Using in SomeComponent
export class SomeComponent implements OnInit {

  constructor(private routerExtService: RouterExtService, private location: Location) { } 

  public back(): void {
    this.location.back();
  }

  //Strange name, but it makes sense. Behind the scenes, we are pushing to history the previous url
  public goToPrevious(): void {
    let previous = this.routerExtService.getPreviousUrl();

    if(previous)
      this.routerExtService.router.navigateByUrl(previous);
  }

  //...

}

2
ฉันคิดว่านี่เป็นทางออกที่สง่างามที่สุด ลองรวมรหัสนี้กับตัวกรองใหม่ & วิธีแก้ปัญหาแบบคู่ของ: stackoverflow.com/a/35287471/518879
danger89

2
Ps. อย่าลืมเพิ่ม RouterExtService นี้ไปยัง apps-routing.module.ts (ในกรณีของฉัน) เช่น:@NgModule({ ..., providers: [RouterExtService]}) export class AppRoutingModule { }
danger89

ตกลงมีปัญหาใหญ่กับโซลูชันบริการนี้ .. ในกรณีของฉันฉันเรียกrouterExtService.getPreviousUrl()เมธอดในตัวสร้างของบริการที่ใช้ในส่วนประกอบ ด้วยเหตุผลบางประการสิ่งนี้เรียกว่าเร็วกว่าการอัปเดตจริง หมายความว่าเรามีการพึ่งพาเวลา! ฉันคิดว่ามันง่ายกว่ามากที่จะใช้ Subject
อันตราย 89

มันใช้งานได้ดีสำหรับฉันในโครงการเล็ก ๆ บางทีอาจต้องปรับแต่งบางอย่างเพื่อให้เหมาะกับความต้องการของคุณ คุณได้แก้ไขปัญหาแล้วหรือยัง?
Juliano

ฉันกำลังใช้พารามิเตอร์ URL Matrixเพื่อ 'เก็บ' สถานะของฉันใน URL ของฉันโดยค่าเริ่มต้น URL ของเบราว์เซอร์จะเก็บสถานะในขณะนี้เมื่อใช้ปุ่มย้อนกลับ let params = new HttpParams({fromString: retrieveURL}).set('name', 'victor') const paramsObject = params.keys().reduce((obj, key) => { obj[key] = params.get(key) return obj }, {}) this.router.navigate([paramsObject], { relativeTo: this.route })
อันตราย 89

20

Angular 6 อัปเดตโค้ดสำหรับรับ url ก่อนหน้าเป็นสตริง

import { Router, RoutesRecognized } from '@angular/router';
import { filter, pairwise } from 'rxjs/operators';


export class AppComponent implements OnInit {

    constructor (
        public router: Router
    ) {
    }

    ngOnInit() {
        this.router.events
            .pipe(filter((e: any) => e instanceof RoutesRecognized),
                pairwise()
            ).subscribe((e: any) => {
                console.log(e[0].urlAfterRedirects); // previous url
            });
    }

สิ่งนี้ส่งคืน url ที่ถูกยามบล็อกมีวิธีรับเฉพาะ url ก่อนหน้านี้ที่เปิดใช้งานแล้ว (ไม่ได้ปิดกั้นโดยยาม) หรือไม่?
Exocomp

1
คำแนะนำใด ๆ เกี่ยวกับวิธีที่ดีที่สุดในการยกเลิกการสมัครจากเราเตอร์ที่สังเกตได้?
j4v1

ได้ผล! ฉันไม่รู้จริงๆว่าทำไม "NavigationEnd" ไม่ทำงาน
davidwillianx

13

สิ่งนี้ใช้ได้ผลสำหรับฉันในเวอร์ชันเชิงมุม> = 6.x:

this.router.events
            .subscribe((event) => {
              if (event instanceof NavigationStart) {
                window.localStorage.setItem('previousUrl', this.router.url);
              }
            });

10

ฉันใช้Angular 8และคำตอบของ @ franklin-pious แก้ปัญหาได้ ในกรณีของฉันรับ url ก่อนหน้าในการสมัครสมาชิกทำให้เกิดผลข้างเคียงบางอย่างหากแนบมาพร้อมกับข้อมูลบางอย่างในมุมมอง

วิธีแก้ปัญหาที่ฉันใช้คือการส่ง url ก่อนหน้านี้เป็นพารามิเตอร์เสริมในการนำทางเส้นทาง

this.router.navigate(['/my-previous-route', {previousUrl: 'my-current-route'}])

และเพื่อรับค่านี้ในส่วนประกอบ:

this.route.snapshot.paramMap.get('previousUrl')

this.router และ this.route ถูกฉีดเข้าไปภายในคอนสตรัคเตอร์ของแต่ละส่วนประกอบและนำเข้าเป็นสมาชิก @ angular / router

import { Router, ActivatedRoute }   from '@angular/router';

10

Angular 8 & rxjs 6 ในเวอร์ชัน 2019

ฉันต้องการแบ่งปันวิธีแก้ปัญหาโดยอิงจากโซลูชันที่ยอดเยี่ยมอื่น ๆ

ขั้นแรกให้บริการเพื่อรับฟังการเปลี่ยนแปลงเส้นทางและบันทึกเส้นทางสุดท้ายก่อนหน้านี้ในหัวข้อพฤติกรรมจากนั้นให้บริการนี้ใน app.component หลักในตัวสร้างจากนั้นใช้บริการนี้เพื่อรับเส้นทางก่อนหน้าที่คุณต้องการเมื่อคุณต้องการ

กรณีการใช้งาน: คุณต้องการเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าโฆษณาจากนั้นจะเปลี่ยนเส้นทางผู้ใช้ไปยังที่ที่มาโดยอัตโนมัติดังนั้นคุณต้องใช้เส้นทางสุดท้ายก่อนหน้านี้

// service : route-events.service.ts

import { Injectable } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { filter, pairwise } from 'rxjs/operators';
import { Location } from '@angular/common';

@Injectable()
export class RouteEventsService {

    // save the previous route
  public previousRoutePath = new BehaviorSubject<string>('');

  constructor(
    private router: Router,
    private location: Location
  ) {

    // ..initial prvious route will be the current path for now
    this.previousRoutePath.next(this.location.path());


    // on every route change take the two events of two routes changed(using pairwise)
    // and save the old one in a behavious subject to access it in another component
    // we can use if another component like intro-advertise need the previous route
    // because he need to redirect the user to where he did came from.
    this.router.events.pipe(
      filter(e => e instanceof RoutesRecognized),
      pairwise(),
        )
    .subscribe((event: any[]) => {
        this.previousRoutePath.next(event[0].urlAfterRedirects);
    });

  }
}

ให้บริการใน app.module

  providers: [
    ....
    RouteEventsService,
    ....
  ]

ฉีดใน app.component

  constructor(
    private routeEventsService: RouteEventsService
  )

สุดท้ายใช้เส้นทางก่อนหน้านี้ที่บันทึกไว้ในองค์ประกอบที่คุณต้องการ

  onSkipHandler(){
    // navigate the user to where he did came from
    this.router.navigate([this.routeEventsService.previousRoutePath.value]);
  }

นี่ใช้งานได้ดีจริงๆ แต่ฉันมีคำถามด่วน คุณเคยยกเลิกการสมัครหรือไม่?
w0ns88

เพิ่ม take (1) แบบนี้ -> pairwise (), take (1)). subscribe ((e: any)
Mukus

1
โปรดทราบว่าหากคุณใช้@Injectable({ providedIn: 'root' })บริการจะถูกโหลดลงในโมดูลรูท (AppModule) ของโปรเจ็กต์โดยอัตโนมัติดังนั้นคุณไม่จำเป็นต้องจัดเตรียมให้กับไฟล์app.module. ดูรายละเอียดในเอกสาร ไม่จำเป็นต้องยกเลิกการสมัครจากเราเตอร์ Observables ตามที่ระบุไว้ในคำตอบ
Hkidd

5

สำหรับ ANGULAR 7+

อันที่จริงเนื่องจาก Angular 7.2 ไม่จำเป็นต้องใช้บริการเพื่อบันทึก url ก่อนหน้านี้ คุณสามารถใช้วัตถุสถานะเพื่อตั้งค่า url สุดท้ายก่อนที่จะเชื่อมโยงไปยังหน้าเข้าสู่ระบบ นี่คือตัวอย่างสำหรับสถานการณ์การเข้าสู่ระบบ

@Component({ ... })
class SomePageComponent {
  constructor(private router: Router) {}

  checkLogin() {
    if (!this.auth.loggedIn()) {
      this.router.navigate(['login'], { state: { redirect: this.router.url } });
    }
  }
}
@Component({...})
class LoginComponent {
  constructor(private router: Router) {}

  backToPreviousPage() {
    const { redirect } = window.history.state;

    this.router.navigateByUrl(redirect || '/homepage');
  }
}
----------------

นอกจากนี้คุณยังสามารถส่งผ่านข้อมูลในเทมเพลต:

@Component({
  template: '<a routerLink="/some-route" [state]="{ redirect: router.url}">Go to some route</a>'
})
class SomePageComponent {
  constructor(public router: Router) {}
}

3

@ GünterZöchbauerคุณสามารถบันทึกไว้ใน localstorage แต่ฉันไม่ชอบ) ดีกว่าที่จะบันทึกในบริการและรับค่านี้จากที่นั่น

 constructor(
        private router: Router
      ) {
        this.router.events
          .subscribe((event) => {
            if (event instanceof NavigationEnd) {
              localStorage.setItem('previousUrl', event.url);
            }
          });
      }

3

คุณสามารถใช้สถานที่เป็นที่กล่าวถึงที่นี่

นี่คือรหัสของฉันหากลิงก์เปิดในแท็บใหม่

navBack() {
    let cur_path = this.location.path();
    this.location.back();
    if (cur_path === this.location.path())
     this.router.navigate(['/default-route']);    
  }

การนำเข้าที่จำเป็น

import { Router } from '@angular/router';
import { Location } from '@angular/common';

0

ค่อนข้างง่ายโดยใช้previousNavigationวัตถุ:

this.router.events
  .pipe(
    filter(e => e instanceof NavigationEnd && this.router.getCurrentNavigation().previousNavigation),
    map(() => this.router.getCurrentNavigation().previousNavigation.finalUrl.toString()),
  )
  .subscribe(previousUrl => {}); 

0

ฉันมีปัญหาในการเข้าถึง url ก่อนหน้าในยาม
โดยไม่ต้องใช้โซลูชันที่กำหนดเองอันนี้ใช้ได้สำหรับฉัน

public constructor(private readonly router: Router) {
};

public ngOnInit() {
   this.router.getCurrentNavigation().previousNavigation.initialUrl.toString();
}

url เริ่มต้นจะเป็นหน้า url ก่อนหน้า


-2

คำตอบข้างต้นทั้งหมดจะโหลด URL หลายครั้ง หากผู้ใช้เยี่ยมชมส่วนประกอบอื่น ๆ ด้วยโค้ดเหล่านี้จะโหลดขึ้น

ดีกว่าที่จะใช้แนวคิดการสร้างบริการ https://community.wia.io/d/22-access-the-previous-route-in-your-angular-5-app

สิ่งนี้จะทำงานได้ดีใน Angular ทุกเวอร์ชัน (โปรดอย่าลืมเพิ่มลงในอาร์เรย์ผู้ให้บริการในไฟล์ app.module ของคุณ!)


-2

การใช้ pairwise จาก rxjx คุณสามารถทำได้ง่ายขึ้น นำเข้า {filter, pairwise} จาก "rxjs / operator";

previousUrl: string;
constructor(router: Router) {
router.events
  .pipe(filter((evt: any) => evt instanceof RoutesRecognized), pairwise())
  .subscribe((events: RoutesRecognized[]) => {
  console.log('previous url', events[0].urlAfterRedirects);
  console.log('current url', events[1].urlAfterRedirects);
  this.previousUrl = events[0].urlAfterRedirects;
});

}


-6

ฉันมีปัญหาคล้ายกันเมื่อฉันต้องการกลับไปที่หน้าที่แล้ว วิธีแก้ปัญหานั้นง่ายกว่าที่ฉันจะจินตนาการได้

<button [routerLink]="['../']">
   Back
</button>

และจะกลับไปที่ url หลัก ฉันหวังว่ามันจะช่วยใครสักคน;)


สิ่งนี้จะไม่ได้ผลคุณกำลังบอกให้ขึ้นบนเส้นทางของเราเตอร์แทนที่จะเป็น url ก่อนหน้าตามที่ OP ระบุ
Frederic Yesid PeñaSánchez

วิธีนี้ใช้ไม่ได้หาก url ของคุณซับซ้อนด้วยพารามิเตอร์หรือไม่มีเส้นทางเดียวกันกับพาเรนต์ ใช้งานได้ก็ต่อเมื่อคุณต้องการย้อนกลับจาก "something / parent / child" เป็น "something / parent"
A. El Idrissi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.