Wie bestimme ich die URL der vorherigen Seite in Angular?

92

Angenommen, ich bin derzeit auf der Seite mit der URL /user/:id. Von dieser Seite navigiere ich nun zur nächsten Seite :id/posts.

Gibt es jetzt einen Weg, damit ich überprüfen kann, was die vorherige URL ist, dh /user/:id.

Unten sind meine Routen

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

Antworten:

76

Sie können Routenänderungen abonnieren und das aktuelle Ereignis speichern, damit Sie es beim nächsten Mal verwenden können

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

Siehe auch Wie erkennt man eine Routenänderung in Angular?

Günter Zöchbauer
quelle
12
Danke @ Günter Du rettest immer meinen Tag.
Chandra Shekhar
24
Dies listet für mich nicht die vorherige Route auf, sondern nur die aktuelle Route.
David Aguirre
2
Kommt darauf an, was du erwartest. Das erste Mal liegt es nulldaran, dass es keine vorherige Route gibt. Sie müssen dies auch auf dem Root-Router tun, da Sie dies sonst nur erhalten, wenn Sie zwischen untergeordneten Routen dieser Komponente navigieren.
Günter Zöchbauer
8
Dies gibt keine vorherige URL an, wenn der Konstruktor zum ersten Mal ausgeführt wird.
Ekaitz Hernandez Troyas
8
Welchen Wert erwarten Sie als vorherige URL, wenn der Konstruktor zum ersten Mal ausgeführt wird?
Günter Zöchbauer
94

Vielleicht sind alle anderen Antworten für Winkel 2.X.

Jetzt funktioniert es nicht mehr für Angular 5.X. Ich arbeite damit.

Mit nur NavigationEnd können Sie keine vorherige URL erhalten.

weil der Router von "NavigationStart", "RoutesRecognized", ... bis "NavigationEnd" arbeitet.

Sie können mit überprüfen

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

Trotzdem können Sie auch mit "NavigationStart" keine vorherige URL erhalten.

Jetzt müssen Sie paarweise verwenden.

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

Mit paarweise können Sie sehen, von welcher URL sie stammt.

"RoutesRecognized" ist der Änderungsschritt vom Ursprung zur Ziel-URL.

Filtern Sie es also und holen Sie sich die vorherige URL.

Zu guter Letzt,

Fügen Sie diesen Code in die übergeordnete Komponente oder höher ein (z. B. app.component.ts).

weil dieser Code nach Beendigung des Routings ausgelöst wird.

Aktualisieren Sie Winkel 6+

Dies events.filtergibt einen Fehler aus, da der Filter nicht Teil von Ereignissen ist. Ändern Sie daher den Code in

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
quelle
2
Als Service implementiert und funktioniert hervorragend. Ich benutze Winkel 6.1.7.
A. El Idrissi
5
@ tjvg1991 Seite aktualisieren bedeutet, dass Sie Speicherdaten verloren haben. Wenn Sie die vorherigen Daten behalten, müssen Sie localStorage oder Cookie verwenden. (Speichern Sie Daten in Ihrem lokalen nicht Speicher)
BYUNGJU JIN
45

Erstellen Sie einen injizierbaren Service:

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

Dann verwenden Sie es überall, wo Sie es brauchen. Um die aktuelle Variable so schnell wie möglich zu speichern, muss der Dienst im AppModule verwendet werden.

// 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
quelle
2
Ich denke, das ist die eleganteste Lösung. Versuchen Sie, diesen Code mit der neuen Filter- und paarweisen Lösung von: stackoverflow.com/a/35287471/518879
gefahr89
1
Ps. Vergessen Sie nicht, diesen RouterExtService wie folgt zu apps-routing.module.ts hinzuzufügen (in meinem Fall):@NgModule({ ..., providers: [RouterExtService]}) export class AppRoutingModule { }
gefahr89
OK, es gibt ein großes Problem mit dieser Servicelösung. In meinem Fall rufe ich die routerExtService.getPreviousUrl()Methode im Konstruktor eines Service auf, der in einer Komponente verwendet wird. Aus irgendeinem Grund wurde dies früher als das eigentliche Update aufgerufen. Das heißt, wir haben eine Timing-Abhängigkeit! Ich denke, es ist viel einfacher, Subject zu verwenden.
Gefahr89
Nun, es hat gut für mich in einem kleinen Projekt funktioniert. Vielleicht muss es etwas angepasst werden, um Ihren Bedürfnissen zu entsprechen. Haben Sie das Problem gelöst?
Juliano
Ich verwende derzeit die sogenannten URL-Matrix-Parameter , um meinen Status in meiner URL zu speichern. Standardmäßig speichert die Browser-URL den Status jetzt, wenn Sie die Schaltfläche "Zurück" verwenden. 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 })
Gefahr89
20

Angular 6 aktualisierter Code zum Abrufen der vorherigen URL als Zeichenfolge.

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 Fromm
quelle
Dies gibt die URL zurück, die von einem Wachmann blockiert wurde. Gibt es eine Möglichkeit, nur die vorherige URL abzurufen, die aktiviert wurde (nicht vom Wachmann blockiert)?
Exocomp
1
Gibt es einen Hinweis, wie Sie sich am besten vom Router abmelden können?
J4V1
Funktioniert! Ich weiß nicht wirklich, warum "NavigationEnd" nicht funktioniert
davidwillianx
13

Dies funktionierte bei mir in eckigen> = 6.x Versionen:

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

Ich benutze Angular 8 und die Antwort von @ franklin-pious löst das Problem. In meinem Fall kann die vorherige URL in einem Abonnement einige Nebenwirkungen verursachen, wenn sie mit einigen Daten in der Ansicht verknüpft ist.

Die Problemumgehung, die ich verwendet habe, bestand darin, die vorherige URL als optionalen Parameter in der Routennavigation zu senden.

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

Und um diesen Wert in der Komponente zu erhalten:

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

this.router und this.route werden in den Konstruktor jeder Komponente eingefügt und als @ angle / router-Mitglieder importiert.

import { Router, ActivatedRoute }   from '@angular/router';
Victor Oliveira
quelle
9

Angular 8 & rxjs 6 in der Version 2019

Ich möchte die Lösung basierend auf anderen großartigen Lösungen teilen.

Erstellen Sie zuerst einen Dienst, um auf Routenänderungen zu warten und die letzte vorherige Route in einem Verhaltensthema zu speichern. Stellen Sie dann diesen Dienst in der Hauptkomponente app.component im Konstruktor bereit und verwenden Sie diesen Dienst, um die gewünschte vorherige Route abzurufen, wann immer Sie möchten.

Anwendungsfall: Sie möchten den Benutzer auf eine Werbeseite umleiten und ihn dann automatisch dorthin umleiten, woher er gekommen ist. Dazu benötigen Sie die letzte vorherige Route.

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

  }
}

Stellen Sie den Service in app.module bereit

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

Injizieren Sie es in app.component

  constructor(
    private routeEventsService: RouteEventsService
  )

Verwenden Sie schließlich die gespeicherte vorherige Route in der gewünschten Komponente

  onSkipHandler(){
    // navigate the user to where he did came from
    this.router.navigate([this.routeEventsService.previousRoutePath.value]);
  }
Louay Alosh
quelle
Das funktioniert wirklich gut. Aber ich habe eine kurze Frage. Melden Sie sich jemals ab?
w0ns88
füge take (1) wie
folgt hinzu
4

FÜR ANGULAR 7+

Seit Angular 7.2 muss kein Dienst zum Speichern der vorherigen URL verwendet werden. Sie können einfach das Statusobjekt verwenden, um die letzte URL festzulegen, bevor Sie auf die Anmeldeseite verlinken. Hier ist ein Beispiel für ein Anmeldeszenario.

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

Zusätzlich können Sie auch die Daten in der Vorlage übergeben:

@Component({
  template: '<a routerLink="/some-route" [state]="{ redirect: router.url}">Go to some route</a>'
})
class SomePageComponent {
  constructor(public router: Router) {}
}
knoefel
quelle
Funktioniert nicht bei Angular 7
Mladen
Welche genaue Version von Angular 7 verwenden Sie?
Knoefel
@Mladen Könnten Sie bitte antworten und bei der Lösung Ihres Problems helfen? Ich vermute, dass Sie nicht mindestens Angular 7.2 verwenden , da dies die erste Version ist, in der die beschriebene Funktionalität hinzugefügt wurde. Könnten Sie dies bitte überprüfen? Vielen Dank!
Knoefel
3

@ GünterZöchbauer auch Sie können es in localstorage speichern, aber ich bevorzuge es nicht) besser im Service zu speichern und diesen Wert von dort zu erhalten

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

Sie können den Standort wie hier erwähnt verwenden .

Hier ist mein Code, wenn der Link auf einer neuen Registerkarte geöffnet wurde

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

Erforderliche Importe

import { Router } from '@angular/router';
import { Location } from '@angular/common';
Waleed Emad
quelle
1

Ziemlich einfach mit previousNavigationObjekt:

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

Ich hatte einige Schwierigkeiten, innerhalb eines Wachmanns auf die vorherige URL zuzugreifen.
Ohne eine benutzerdefinierte Lösung zu implementieren, funktioniert diese für mich.

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

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

Die anfängliche URL ist die vorherige URL-Seite.

C0ZEN
quelle
0

Für die Verwendung in einem Winkel von 6/7 oder höher sollten Sie ein Rohr und einen Betriebsfilter verwenden

import {Router, NavigationEnd} form "@angular/router";
import { filter } from 'rxjs/operators';

...
previousUrl:string;

constructor(private router:Router){}

ngOnInit(){

      this.router.events
            .pipe(
                filter(event => event instanceof NavigationEnd)
            )
            .subscribe((e :any)=> {
                console.log('prev:', this.previousUrl);
                this.previousUrl = e.url;
            });
}
Hassan Khademi
quelle
-1

Alle oben genannten ANTWORTEN werden mehrmals als URL geladen. Wenn der Benutzer auch eine andere Komponente besucht hat, wird dieser Code geladen.

Also besser zu bedienen, Service-Erstellungskonzept. https://community.wia.io/d/22-access-the-previous-route-in-your-angular-5-app

Dies funktioniert in allen Versionen von Angular. (Bitte stellen Sie sicher, dass Sie es dem Provider-Array in Ihrer app.module-Datei hinzufügen!)

ABHILASHA KM
quelle
-1

Mit paarweise von rxjx können Sie dies einfacher erreichen. {filter, pairwise} aus 'rxjs / operator' importieren;

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
quelle
-5

Ich hatte ein ähnliches Problem, als ich zur vorherigen Seite zurückkehren wollte. Die Lösung war einfacher als ich mir vorstellen konnte.

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

Und es kehrt zur übergeordneten URL zurück. Ich hoffe es wird jemandem helfen;)

DiPix
quelle
Dies wird nicht funktionieren. Sie werden aufgefordert, den Pfad des Routers zu wählen und nicht die vorherige URL, wie im OP angegeben.
Frederic Yesid Peña Sánchez
Dies funktioniert nicht, wenn Ihre URL mit Parametern komplex ist oder nicht denselben Pfad wie die übergeordnete hat. Es funktioniert nur, wenn Sie von "etwas / Eltern / Kind" zu "etwas / Eltern" zurückkehren möchten.
A. El Idrissi