Làm thế nào để xác định URL trang trước trong Angular?


99

Giả sử tôi hiện đang ở trên trang có URL /user/:id . Bây giờ từ trang này, tôi điều hướng đến trang tiếp theo :id/posts.

Bây giờ Có cách nào để tôi có thể kiểm tra URL trước đó là gì không, tức là /user/:id.

Dưới đây là các tuyến đường của tôi

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

Câu trả lời:


80

Bạn có thể đăng ký thay đổi lộ trình và lưu trữ sự kiện hiện tại để có thể sử dụng khi sự kiện tiếp theo xảy ra

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;
  });
}

Xem thêm Cách phát hiện thay đổi tuyến đường trong Angular?


12
Cảm ơn @ Günter Bạn luôn tiết kiệm ngày của tôi.
Chandra Shekhar

28
Điều này không liệt kê các tuyến đường trước đó cho tôi, chỉ có tuyến đường hiện tại.
David Aguirre

2
Phụ thuộc vào những gì bạn mong đợi. Lần đầu là nullvì không có lộ trình trước. Bạn cũng cần thực hiện việc này trên bộ định tuyến gốc, nếu không bạn sẽ chỉ nhận được khi điều hướng giữa các tuyến con của thành phần này.
Günter Zöchbauer

8
Điều này không cung cấp url trước đó khi hàm tạo được thực thi lần đầu tiên.
Ekaitz Hernandez Troyas,

9
Bạn mong đợi giá trị nào làm url trước đó khi hàm tạo được thực thi lần đầu tiên?
Günter Zöchbauer

108

Có thể tất cả các câu trả lời khác dành cho góc 2.X.

Bây giờ nó không hoạt động cho góc 5.X. Tôi đang làm việc với nó.

chỉ với NavigationEnd, bạn không thể lấy url trước đó.

vì Router hoạt động từ "NavigationStart", "RoutesRecognized", ..., thành "NavigationEnd".

Bạn có thể kiểm tra với

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

Nhưng bạn vẫn không thể nhận được url trước đó ngay cả với "NavigationStart".

Bây giờ bạn cần sử dụng ghép nối.

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);
    });
}
    

Với từng cặp, Bạn có thể xem url là từ và đến.

"RoutesRecognized" là bước thay đổi từ url gốc đến url đích.

vì vậy hãy lọc nó và lấy url trước đó từ nó.

Cuối cùng nhưng không kém phần quan trọng,

đặt mã này trong thành phần chính hoặc cao hơn (ví dụ: app.component.ts)

vì mã này kích hoạt sau khi kết thúc định tuyến.

Cập nhật góc 6+

Các events.filtercho lỗi vì bộ lọc không phải là một phần của sự kiện, vì vậy thay đổi mã để

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
Được triển khai như một dịch vụ và nó hoạt động tuyệt vời. Tôi đang sử dụng góc 6.1.7.
A. El Idrissi

5
@ tjvg1991 Đang làm mới trang có nghĩa là bạn đã mất dữ liệu bộ nhớ. nếu bạn giữ dữ liệu trước đó, bạn cần sử dụng localStorage hoặc cookie. (lưu dữ liệu tại bộ nhớ cục bộ không phải bộ nhớ cục bộ của bạn)
BYUNGJU JIN

Tôi chỉ muốn giết nút Upvote Cảm ơn anh bạn.
Muhammad Umair

@BYUNGJUJIN Cảm ơn vì điều này!
john

@ BYUNGJU JIN cảm ơn bạn đã làm việc cho tôi. làm cách nào để lấy giá trị của param từ liên kết chuyển hướng, ví dụ như sự kiện [0] .urlAfterRedirects cung cấp cho tôi '/ stockDetails; test = 0; id = 45', tôi muốn lấy giá trị của id từ liên kết này. Làm thế nào tôi có thể làm mà không sử dụng chuỗi con.
JNPW

49

Tạo một dịch vụ tiêm:

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;
  }    
}

Sau đó sử dụng nó ở mọi nơi bạn cần. Để lưu trữ biến hiện tại càng sớm càng tốt, bạn cần sử dụng dịch vụ trong 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
Tôi nghĩ rằng đây là giải pháp thanh lịch nhất. Cố gắng kết hợp mã này với bộ lọc & cặp giải pháp mới của: stackoverflow.com/a/35287471/518879
danger89

2
Ps. Đừng quên thêm RouterExtService này vào apps-routing.module.ts (trong trường hợp của tôi), như vậy:@NgModule({ ..., providers: [RouterExtService]}) export class AppRoutingModule { }
risk89

OK, có một vấn đề lớn với giải pháp dịch vụ này .. Trong trường hợp của tôi, tôi gọi routerExtService.getPreviousUrl()phương thức trong phương thức khởi tạo của một dịch vụ được sử dụng trong một thành phần. Vì một số lý do, điều này được gọi sớm hơn so với bản cập nhật thực tế. Có nghĩa là chúng ta có một sự phụ thuộc vào thời gian! Tôi nghĩ rằng nó dễ dàng hơn để sử dụng Chủ đề.
nguy hiểm 89,

Chà, nó hoạt động tốt đối với tôi trong một dự án nhỏ. Có lẽ nó cần một số tinh chỉnh để phù hợp với nhu cầu của bạn. Bạn đã giải quyết được vấn đề chưa?
Juliano

Tôi hiện đang sử dụng cái gọi là tham số Ma trận URL để 'lưu trữ' trạng thái của tôi trong URL của tôi, theo mặc định, URL của trình duyệt lưu trữ trạng thái ngay bây giờ khi sử dụng nút quay lại. 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 })
nguy hiểm 89

20

Mã đã cập nhật Angular 6 để lấy url trước đó dưới dạng chuỗi.

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
            });
    }

Điều này trả về url đã bị chặn bởi người bảo vệ, có cách nào để chỉ lấy url trước đó đã được kích hoạt (không bị chặn bởi người bảo vệ) không?
Exocomp

1
Bất kỳ gợi ý nào về cách tốt nhất để hủy đăng ký khỏi bộ định tuyến có thể quan sát được?
j4v1

Làm! Tôi thật sự không biết tại sao "NavigationEnd" không làm việc
davidwillianx

13

Điều này làm việc cho tôi trong các phiên bản góc> = 6.x:

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

11

Angular 8 & rxjs 6 trong phiên bản 2019

Tôi muốn chia sẻ giải pháp dựa trên những giải pháp tuyệt vời khác.

Trước tiên, hãy tạo một dịch vụ để lắng nghe các thay đổi về tuyến đường và lưu tuyến đường trước đó cuối cùng trong Chủ đề hành vi, sau đó cung cấp dịch vụ này trong app.component chính trong hàm tạo, sau đó sử dụng dịch vụ này để nhận tuyến đường trước đó bạn muốn bất cứ khi nào bạn muốn.

trường hợp sử dụng: bạn muốn chuyển hướng người dùng đến một trang quảng cáo sau đó tự động chuyển hướng họ đến nơi họ đến, vì vậy bạn cần tuyến đường trước đó cuối cùng để thực hiện.

// 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);
    });

  }
}

cung cấp dịch vụ trong app.module

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

Tiêm nó trong app.component

  constructor(
    private routeEventsService: RouteEventsService
  )

cuối cùng sử dụng tuyến đường trước đó đã lưu trong thành phần bạn muốn

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

Điều này thực sự hoạt động tốt. Nhưng tôi có một câu hỏi nhanh. Bạn có bao giờ hủy đăng ký không?
w0ns88

thêm take (1) như thế này -> pairwise (), take (1)). subscribe ((e: any)
Mukus

1
Lưu ý rằng nếu bạn sử dụng @Injectable({ providedIn: 'root' })dịch vụ sẽ được tự động tải vào mô-đun gốc (AppModule) của dự án và do đó bạn không phải cung cấp thủ công cho app.module. Xem tài liệu để biết chi tiết. Không cần thiết phải hủy đăng ký nhận router Observables như đã nêu trong câu trả lời
Hkidd

10

Tôi đang sử dụng Angular 8 và câu trả lời của @ Franklin-pious giải quyết được vấn đề. Trong trường hợp của tôi, lấy url trước đó bên trong đăng ký gây ra một số tác dụng phụ nếu nó được đính kèm với một số dữ liệu trong chế độ xem.

Cách giải quyết mà tôi đã sử dụng là gửi url trước đó dưới dạng tham số tùy chọn trong điều hướng tuyến đường.

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

Và để nhận giá trị này trong thành phần:

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

this.router và this.route được đưa vào bên trong hàm tạo của mỗi thành phần và được nhập dưới dạng thành viên @ angle / router.

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

5

DÀNH CHO ANGULAR 7+

Trên thực tế, kể từ Angular 7.2, không cần sử dụng dịch vụ để lưu url trước đó. Bạn chỉ có thể sử dụng đối tượng trạng thái để đặt url cuối cùng trước khi liên kết đến trang đăng nhập. Đây là một ví dụ cho một tình huống đăng nhập.

@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');
  }
}
----------------

Ngoài ra, bạn cũng có thể chuyển dữ liệu trong mẫu:

@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 bạn cũng có thể lưu nó trong localstorage nhưng tôi không thích nó) tốt hơn nên lưu trong dịch vụ và nhận giá trị này từ đó

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

3

Bạn có thể sử dụng Vị trí như đã đề cập ở đây .

Đây là mã của tôi nếu liên kết được mở trên tab mới

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

Nhập khẩu bắt buộc

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

1

Khá đơn giản bằng cách sử dụng previousNavigationđối tượng:

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

1

Tôi đã gặp một số khó khăn để truy cập vào url trước đó bên trong một trình bảo vệ.
Không cần triển khai giải pháp tùy chỉnh, giải pháp này đang làm việc cho tôi.

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

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

Url ban đầu sẽ là trang url trước đó.


-2

Tất cả CÂU TRẢ LỜI Ở Trên sẽ được tải URL nhiều lần. Nếu người dùng cũng đã truy cập bất kỳ thành phần nào khác, thì mã này sẽ tải.

Vì vậy, tốt hơn để sử dụng, Dịch vụ tạo khái niệm. https://community.wia.io/d/22-access-the-previous-route-in-your-angular-5-app

Điều này sẽ hoạt động tốt trong tất cả các phiên bản của Angular. (hãy đảm bảo thêm nó vào mảng nhà cung cấp trong tệp app.module của bạn!)


-2

Sử dụng cặp từ rxjx, bạn có thể đạt được điều này dễ dàng hơn. nhập {filter, pairwise} từ '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

Tôi đã gặp vấn đề tương tự khi tôi muốn quay lại trang trước. Giải pháp dễ dàng hơn tôi có thể tưởng tượng.

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

Và nó trở về url mẹ. Tôi hy vọng nó sẽ giúp ai đó;)


Điều này sẽ không hoạt động, bạn đang nói đi lên trên đường dẫn của bộ định tuyến, thay vì url trước đó như OP đã nêu.
Frederic Yesid Peña Sánchez

Điều này không hoạt động nếu url của bạn phức tạp với các tham số hoặc không có cùng đường dẫn với nguồn gốc. Nó chỉ hoạt động nếu bạn muốn quay lại từ "something / parent / child" thành "something / parent".
A. El Idrissi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.