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.