Jak określić adres URL poprzedniej strony w Angular?


104

Załóżmy, że aktualnie jestem na stronie, która ma adres URL /user/:id. Teraz z tej strony przechodzę do następnej strony :id/posts.

Czy jest sposób, żebym mógł sprawdzić, jaki jest poprzedni adres URL, tj /user/:id.

Poniżej moje trasy

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

Odpowiedzi:


83

Możesz zasubskrybować zmiany tras i przechowywać bieżące wydarzenie, aby móc z niego skorzystać, gdy wydarzy się następne

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

Zobacz także Jak wykryć zmianę trasy w Angular?


12
Dzięki @ Günter Zawsze ratujesz mój dzień.
Chandra Shekhar

34
Nie jest to dla mnie lista poprzedniej trasy, tylko aktualna trasa.
David Aguirre,

2
Zależy od tego, czego oczekujesz. Za pierwszym razem to nulldlatego , że nie ma poprzedniej trasy. Musisz to również zrobić na routerze głównym, w przeciwnym razie uzyskasz tylko podczas nawigacji między trasami podrzędnymi tego komponentu.
Günter Zöchbauer

8
To nie daje poprzedniego adresu URL, gdy konstruktor jest wykonywany po raz pierwszy.
Ekaitz Hernandez Troyas

9
Jakiej wartości oczekujesz jako poprzedniego adresu URL, gdy konstruktor jest wykonywany po raz pierwszy?
Günter Zöchbauer

114

Może wszystkie inne odpowiedzi dotyczą Angular 2.X.

Teraz nie działa dla kątowej 5.X. Pracuję z tym.

mając tylko NavigationEnd, nie można uzyskać poprzedniego adresu URL.

ponieważ Router działa od „NavigationStart”, „RoutesRecognized”, ..., do „NavigationEnd”.

Możesz to sprawdzić

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

Ale nadal nie możesz uzyskać poprzedniego adresu URL, nawet z "NavigationStart".

Teraz musisz użyć parowania.

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

Dzięki parowaniu możesz zobaczyć, jaki jest adres URL od i do.

„RoutesRecognized” to krok zmiany od początku do docelowego adresu URL.

więc przefiltruj go i pobierz z niego poprzedni adres URL.

Nie mniej ważny,

umieść ten kod w komponencie nadrzędnym lub wyższym (np. app.component.ts)

ponieważ ten kod jest uruchamiany po zakończeniu routingu.

Zaktualizuj kątową 6+

events.filterDaje błąd, ponieważ filtr nie jest częścią wydarzeń, więc zmiany kodu do

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
Wdrożony jako usługa i działa świetnie. Używam kątowego 6.1.7.
A. El Idrissi

5
@ tjvg1991 Odświeżająca się strona oznacza utratę danych pamięci. jeśli zachowujesz poprzednie dane, musisz użyć localStorage lub cookie. (zapisuj dane w lokalnej pamięci, a nie w pamięci)
BYUNGJU JIN

@BYUNGJUJIN Dzięki za to!
john,

1
@BYUNGJUIN przechowuje zwracaną wartość subscribe()w polu i wywołuje unsubscribe()ją w ngOnDestroy(). Powinny być odcinki. pytania z przykładami anulowania subskrypcji tutaj na SO.
Günter Zöchbauer

1
@app, sprawdź to, aby zrezygnować z subskrypcji: malcontentboffin.com/2017/12/…
BYUNGJU JIN

51

Utwórz usługę do wstrzykiwania:

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

Następnie używaj go wszędzie tam, gdzie potrzebujesz. Aby jak najszybciej zapisać aktualną zmienną, konieczne jest skorzystanie z usługi w 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
Myślę, że to najbardziej eleganckie rozwiązanie. Spróbuj połączyć ten kod z nowym filtrem i rozwiązaniem parami: stackoverflow.com/a/35287471/518879
niebezpieczeństwo89

2
Ps. Nie zapomnij dodać tego RouterExtService do pliku apps-routing.module.ts (w moim przypadku), na przykład:@NgModule({ ..., providers: [RouterExtService]}) export class AppRoutingModule { }
niebezpieczeństwo89

OK, jest duży problem z tym rozwiązaniem usługi. W moim przypadku routerExtService.getPreviousUrl()metodę wywołuję w konstruktorze usługi używanej w komponencie. Z jakiegoś powodu zadzwoniło to wcześniej niż faktyczna aktualizacja. Oznacza to, że mamy zależność czasową! Myślę, że temat jest znacznie łatwiejszy w użyciu.
niebezpieczeństwo89

Cóż, działało dobrze dla mnie w małym projekcie. Może wymaga pewnych poprawek, aby dopasować je do Twoich potrzeb. Czy rozwiązałeś problem?
Juliano

Obecnie używam tak zwanych parametrów macierzy adresów URL, aby „przechowywać” mój stan w moim adresie URL, domyślnie adres URL przeglądarki przechowuje stan teraz, gdy używam przycisku Wstecz. 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 })
niebezpieczeństwo89

20

Angular 6 zaktualizował kod do pobierania poprzedniego adresu URL jako łańcucha.

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

Powoduje to zwrócenie adresu URL, który został zablokowany przez strażnika. Czy istnieje sposób, aby uzyskać tylko poprzedni adres URL, który został aktywowany (nie został zablokowany przez strażnika)?
Exocomp

1
Czy są jakieś wskazówki dotyczące najlepszego sposobu wypisania się z routera?
j4v1

Pracuje! Naprawdę nie wiem, dlaczego „NavigationEnd” nie działa
davidwillianx,

13

To zadziałało dla mnie w wersjach kątowych> = 6.x:

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

11

Używam Angular 8 i odpowiedź @ franklin-pious rozwiązuje problem. W moim przypadku pobranie poprzedniego adresu URL w ramach subskrypcji powoduje pewne skutki uboczne, jeśli jest dołączone do niektórych danych w widoku.

Obejście, którego użyłem, polegało na wysłaniu poprzedniego adresu URL jako opcjonalnego parametru w nawigacji po trasie.

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

Aby uzyskać tę wartość w komponencie:

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

this.router i this.route są wstawiane do konstruktora każdego komponentu i importowane jako elementy @ angular / router.

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

10

Angular 8 i rxjs 6 w wersji 2019

Chciałbym podzielić się rozwiązaniem opartym na innych świetnych rozwiązaniach.

Najpierw wykonaj usługę nasłuchiwania zmian tras i zapisz ostatnią poprzednią trasę w temacie zachowania, a następnie udostępnij tę usługę w głównym komponencie app.com w konstruktorze, a następnie użyj tej usługi, aby uzyskać poprzednią trasę, którą chcesz, kiedy chcesz.

przypadek użycia: chcesz przekierować użytkownika na stronę z ogłoszeniami, a następnie automatycznie przekierować go / ją tam, skąd przyszedł, więc potrzebujesz ostatniej poprzedniej trasy, aby to zrobić.

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

  }
}

świadczyć usługę w app.module

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

Wstrzyknij go w app.component

  constructor(
    private routeEventsService: RouteEventsService
  )

na koniec użyj zapisanej poprzedniej trasy w wybranym komponencie

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

To działa naprawdę dobrze. Ale mam krótkie pytanie. Czy kiedykolwiek wypisałeś się z subskrypcji?
w0ns88

dodaj take (1) w ten sposób -> pairwise (), take (1)). subskrybuj ((e: any)
Mukus

1
Zwróć uwagę, że jeśli korzystasz @Injectable({ providedIn: 'root' })z usługi, jest ona automatycznie ładowana do modułu głównego (AppModule) projektu, a zatem nie musisz ręcznie dostarczać jej do app.module. Szczegółowe informacje można znaleźć w dokumentacji . Nie jest konieczne anulowanie subskrypcji routera Observables, jak podano w tej odpowiedzi
Hkidd

7

DLA KĄTOWEGO 7+

Właściwie od Angulara 7.2 nie ma potrzeby korzystania z usługi do zapisywania poprzedniego adresu URL. Możesz po prostu użyć obiektu stanu, aby ustawić ostatni adres URL przed połączeniem ze stroną logowania. Oto przykład scenariusza logowania.

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

Dodatkowo możesz też przekazać dane w szablonie:

@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 również możesz zapisać go w lokalnym magazynie, ale nie wolę tego) lepiej zapisać w serwisie i stamtąd uzyskać tę wartość

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

3

Możesz użyć lokalizacji, jak wspomniano tutaj .

Oto mój kod, jeśli link został otwarty w nowej karcie

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

Wymagany import

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

0

Całkiem proste przy użyciu previousNavigationobiektu:

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

0

Miałem trudności z uzyskaniem dostępu do poprzedniego adresu URL wewnątrz strażnika.
Bez wdrażania niestandardowego rozwiązania to działa dla mnie.

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

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

Początkowy adres URL będzie poprzednią stroną adresu URL.


0

To proste rozwiązanie zadziałało dla mnie.

import 'rxjs/add/operator/pairwise';
import { Router } from '@angular/router';

export class TempComponent {
    constructor(private router: Router) {
        this.router.events.pairwise().subscribe((event) => {
            console.log(event); // NavigationEnd will have last and current visit url
        });
    };
}


-2

Używając parami z rxjx, możesz to osiągnąć łatwiej. import {filter, pairwise} z 'rxjs / operators';

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

Miałem podobny problem, gdy chciałem wrócić do poprzedniej strony. Rozwiązanie było łatwiejsze, niż mogłem sobie wyobrazić.

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

I wraca do nadrzędnego adresu URL. Mam nadzieję, że komuś to pomoże;)


To nie zadziała, mówisz, aby przejść do ścieżki routera, a nie do poprzedniego adresu URL, jak podał OP.
Frederic Yesid Peña Sánchez

To nie działa, jeśli Twój adres URL jest złożony z parametrami lub ma inną ścieżkę niż nadrzędny. Działa tylko wtedy, gdy chcesz wrócić z „czegoś / rodzica / dziecka” do „czegoś / rodzica”.
A. El Idrissi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.