Bagaimana cara menentukan URL halaman sebelumnya di Angular?

101

Misalkan saya saat ini berada di halaman yang memiliki URL /user/:id. Sekarang dari halaman ini saya menavigasi ke halaman berikutnya :id/posts.

Sekarang apakah ada cara, sehingga saya dapat memeriksa apa URL sebelumnya, yaitu /user/:id.

Berikut adalah rute saya

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

Jawaban:

80

Anda dapat berlangganan perubahan rute dan menyimpan acara saat ini sehingga Anda dapat menggunakannya saat acara berikutnya

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

Lihat juga Bagaimana mendeteksi perubahan rute di Angular?

Günter Zöchbauer
sumber
12
Terima kasih @ Günter Anda selalu menyelamatkan hari saya.
Chandra Shekhar
29
Ini tidak mencantumkan rute sebelumnya untuk saya, hanya rute saat ini.
David Aguirre
2
Tergantung apa yang Anda harapkan. Pertama kali nullkarena tidak ada rute sebelumnya. Anda juga perlu melakukan ini di root router, jika tidak, Anda hanya akan mendapatkannya saat menavigasi di antara rute turunan komponen ini.
Günter Zöchbauer
8
Ini tidak memberikan url sebelumnya saat konstruktor dijalankan untuk pertama kali.
Ekaitz Hernandez Troyas
9
Nilai apa yang Anda harapkan sebagai url sebelumnya ketika konstruktor dijalankan untuk pertama kali?
Günter Zöchbauer
109

Mungkin semua jawaban lainnya adalah untuk sudut 2.X.

Sekarang tidak berfungsi untuk sudut 5.X. Saya sedang mengerjakannya.

hanya dengan NavigationEnd, Anda tidak bisa mendapatkan url sebelumnya.

karena Router bekerja dari "NavigationStart", "RoutesRecognized", ..., hingga "NavigationEnd".

Anda bisa mengeceknya dengan

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

Tapi tetap saja Anda tidak bisa mendapatkan url sebelumnya bahkan dengan "NavigationStart".

Sekarang Anda perlu menggunakan berpasangan.

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

Dengan berpasangan, Anda dapat melihat asal dan tujuan url.

"RoutesRecognized" adalah langkah perubahan dari asal ke url target.

jadi filter dan dapatkan url sebelumnya darinya.

Terakhir tapi bukan yang akhir,

letakkan kode ini di komponen induk atau yang lebih tinggi (mis., app.component.ts)

karena kode ini aktif setelah perutean selesai.

Perbarui sudut 6+

The events.filtermemberikan kesalahan karena filter bukan bagian dari acara, sehingga mengubah kode untuk

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);
});
BYUNGJU JIN
sumber
2
Diimplementasikan sebagai layanan dan berfungsi dengan baik. Saya menggunakan sudut 6.1.7.
A. El Idrissi
5
@ tjvg1991 Menyegarkan halaman berarti Anda kehilangan data memori. jika Anda menyimpan data sebelumnya, Anda perlu menggunakan localStorage atau cookie. (simpan data di lokal Anda bukan memori)
BYUNGJU JIN
Saya hanya ingin mematikan tombol Suara Terima. Terima kasih.
Muhammad Umair
@BYUNGJUJIN Terima kasih untuk ini!
john
@ BYUNGJU JIN terima kasih bekerja untuk saya. bagaimana cara mendapatkan nilai param dari tautan pengalihan katakanlah misalnya peristiwa [0] .urlAfterRedirects memberi saya '/ inventoryDetails; test = 0; id = 45', saya ingin mendapatkan nilai id dari ini. Bagaimana saya bisa melakukannya tanpa menggunakan subString.
JNPW
49

Buat layanan injeksi:

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

Kemudian gunakan di mana pun Anda membutuhkannya. Untuk menyimpan variabel saat ini sesegera mungkin, Anda perlu menggunakan layanan di 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);
  }

  //...

}
Juliano
sumber
2
Saya rasa ini adalah solusi paling elegan. Coba gabungkan kode ini dengan filter baru & solusi berpasangan: stackoverflow.com/a/35287471/518879
hazard89
2
Ps. Jangan lupa untuk menambahkan RouterExtService ini ke apps-routing.module.ts (dalam kasus saya), seperti:@NgModule({ ..., providers: [RouterExtService]}) export class AppRoutingModule { }
hazard89
Oke, ada masalah besar dengan solusi layanan ini .. Dalam kasus saya, saya memanggil routerExtService.getPreviousUrl()metode dalam konstruktor layanan yang digunakan dalam komponen. Untuk beberapa alasan ini disebut lebih awal dari pembaruan yang sebenarnya. Artinya kita memiliki ketergantungan waktu! Saya pikir lebih mudah menggunakan Subjek.
hazard89
Yah, itu bekerja dengan baik untuk saya dalam proyek kecil. Mungkin perlu beberapa penyesuaian agar sesuai dengan kebutuhan Anda. Sudahkah Anda memecahkan masalah tersebut?
Juliano
Saat ini saya menggunakan apa yang disebut parameter Matriks URL untuk 'menyimpan' status saya di URL saya, secara default URL browser menyimpan status sekarang saat menggunakan tombol kembali. 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 })
hazard89
20

Angular 6 memperbarui kode untuk mendapatkan url sebelumnya sebagai string.

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
            });
    }
Franklin Pious
sumber
Ini mengembalikan url yang telah diblokir oleh penjaga, apakah ada cara untuk hanya mendapatkan url sebelumnya yang telah diaktifkan (tidak diblokir oleh penjaga)?
Exocomp
1
Adakah petunjuk tentang cara terbaik untuk berhenti berlangganan dari router yang dapat diamati?
j4v1
Bekerja! Saya tidak begitu tahu Mengapa "NavigationEnd" tidak berfungsi
davidwillianx
13

Ini bekerja untuk saya dalam versi angular> = 6.x:

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

Saya menggunakan Angular 8 dan jawaban dari @ franklin-pious memecahkan masalah. Dalam kasus saya, dapatkan url sebelumnya di dalam langganan menyebabkan beberapa efek samping jika dilampirkan dengan beberapa data dalam tampilan.

Solusi yang saya gunakan adalah mengirim url sebelumnya sebagai parameter opsional dalam navigasi rute.

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

Dan untuk mendapatkan nilai ini di komponen:

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

this.router dan this.route dimasukkan ke dalam konstruktor setiap komponen dan diimpor sebagai anggota @ angular / router.

import { Router, ActivatedRoute }   from '@angular/router';
Victor Oliveira
sumber
10

Angular 8 & rxjs 6 pada versi 2019

Saya ingin berbagi solusi berdasarkan solusi hebat lainnya.

Pertama-tama buat layanan untuk mendengarkan perubahan rute dan simpan rute terakhir sebelumnya di Subjek Perilaku, lalu sediakan layanan ini di app.component utama di konstruktor lalu gunakan layanan ini untuk mendapatkan rute sebelumnya yang Anda inginkan kapan pun Anda mau.

kasus penggunaan: Anda ingin mengarahkan pengguna ke halaman beriklan kemudian secara otomatis mengarahkannya ke tempat asalnya sehingga Anda memerlukan rute terakhir sebelumnya untuk melakukannya.

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

  }
}

menyediakan layanan di app.module

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

Masukkan di app.component

  constructor(
    private routeEventsService: RouteEventsService
  )

terakhir gunakan rute sebelumnya yang disimpan di komponen yang Anda inginkan

  onSkipHandler(){
    // navigate the user to where he did came from
    this.router.navigate([this.routeEventsService.previousRoutePath.value]);
  }
Louay Alosh
sumber
Ini bekerja dengan sangat baik. Tapi saya punya pertanyaan singkat. Apakah Anda pernah berhenti berlangganan?
w0ns88
tambahkan take (1) seperti ini -> pairwise (), take (1)). subscribe ((e: any)
Mukus
1
Perhatikan bahwa jika Anda menggunakan @Injectable({ providedIn: 'root' })layanan, secara otomatis dimuat ke dalam modul root (AppModule) proyek dan karenanya Anda tidak perlu menyediakannya secara manual ke app.module. Lihat dokumen untuk detailnya. Tidak perlu berhenti berlangganan dari Observables router seperti yang dinyatakan dalam jawaban
Hkidd
5

UNTUK ANGULAR 7+

Sebenarnya sejak Angular 7.2 tidak perlu menggunakan layanan untuk menyimpan url sebelumnya. Anda bisa menggunakan objek status untuk menyetel url terakhir sebelum menautkan ke halaman login. Berikut adalah contoh skenario login.

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

Selain itu, Anda juga bisa meneruskan data di template:

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

@ GünterZöchbauer juga Anda dapat menyimpannya di penyimpanan lokal tetapi saya tidak lebih suka) lebih baik menyimpan dalam layanan dan mendapatkan nilai ini dari sana

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

Anda dapat menggunakan Lokasi seperti yang disebutkan di sini .

Ini kode saya jika tautan dibuka di tab baru

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

Impor yang dibutuhkan

import { Router } from '@angular/router';
import { Location } from '@angular/common';
Waleed Emad
sumber
0

Cukup sederhana dengan menggunakan previousNavigationobjek:

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

Saya kesulitan mengakses url sebelumnya di dalam penjaga.
Tanpa menerapkan solusi khusus, yang ini berfungsi untuk saya.

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

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

Url awal akan menjadi halaman url sebelumnya.

C0ZEN
sumber
-2

Menggunakan berpasangan dari rxjx Anda dapat mencapai ini dengan lebih mudah. impor {filter, pairwise} dari '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;
});

}

Ashraf Ali
sumber
-6

Saya mengalami masalah serupa ketika saya ingin kembali ke halaman sebelumnya. Solusi lebih mudah dari yang bisa saya bayangkan.

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

Dan itu kembali ke url induk. Saya berharap ini akan membantu seseorang;)

DiPix
sumber
Ini tidak akan berfungsi, Anda memberi tahu untuk naik di jalur router, daripada url sebelumnya seperti yang dinyatakan OP.
Frederic Yesid Peña Sánchez
Ini tidak berfungsi jika url Anda rumit dengan parameter, atau tidak memiliki jalur yang sama dengan induknya. Ini hanya berfungsi jika Anda ingin kembali dari "sesuatu / orang tua / anak" ke "sesuatu / orang tua".
A. El Idrissi