Comment revenir à la dernière page

370

Existe-t-il un moyen intelligent de retourner à la dernière page d'Angular 2?

Quelque chose comme

this._router.navigate(LASTPAGE);

Par exemple, la page C a un Go Backbouton,

  • Page A -> Page C, cliquez dessus, retour à la page A.

  • Page B -> Page C, cliquez dessus, retour à la page B.

Le routeur possède-t-il ces informations d'historique?

Hongbo Miao
la source

Réponses:

673

En fait, vous pouvez profiter du service de localisation intégré, qui possède une API «Retour».

Ici (en TypeScript):

import {Component} from '@angular/core';
import {Location} from '@angular/common';

@Component({
  // component's declarations here
})
class SomeComponent {

  constructor(private _location: Location) 
  {}

  backClicked() {
    this._location.back();
  }
}

Edit : Comme mentionné par @ charith.arumapperuma Locationdoit être importé de @angular/commonsorte que la import {Location} from '@angular/common';ligne est importante.

Amir Sasson
la source
75
L'emplacement doit être importé de "angular2 / router" dans les anciennes versions d'Angular 2. Dans les versions plus récentes, il doit provenir de "@ angular / common".
charith.arumapperuma
2
Si vous l'avez intégré dans le framework, je ne vois aucune raison d'utiliser le "native" "window.history.back ();" qui est une fonctionnalité HTML5 ( developer.mozilla.org/en-US/docs/Web/API/Window/history )
Amir Sasson
7
Pour ce que cela vaut, la documentation officielle de l'API Angular2 pour les Locationétats: "Remarque: il est préférable d'utiliser le service de routeur pour déclencher des changements de route. N'utilisez l'emplacement que si vous devez interagir avec ou créer des URL normalisées en dehors du routage." La réponse de @ Sasxa montre apparemment un moyen Routerde le faire. Cependant, la Locationméthode est certainement plus pratique. Est-ce que quelqu'un sait pourquoi la Routerméthode pourrait être plus correcte que la Locationméthode?
Andrew Willems
2
@Andrew: J'ai rencontré le problème, vous ne pouvez pas revenir en arrière deux fois, si vous utilisez this.location.back (). Vous reviendrez au site initial.
Johannes
1
@ yt61, pas sûr, peut-être réutilisation? ou si vous pouvez accéder à une page spécifiée à partir de divers itinéraires, vous ne savez donc pas à l'avance l'itinéraire vers lequel revenir.
Amir Sasson
112

Dans la version finale d'Angular 2.x / 4.x - voici la documentation https://angular.io/api/common/Location

/* typescript */

import { Location } from '@angular/common';
// import stuff here

@Component({
// declare component here
})
export class MyComponent {

  // inject location into component constructor
  constructor(private location: Location) { }

  cancel() {
    this.location.back(); // <-- go back to previous location on cancel
  }
}
Hinrich
la source
1
En revenant à l'écran précédent, nous pouvons conserver les valeurs saisies sans utiliser d'objet en service.
Vignesh
Comment afficher l'animation pendant l'exécution de location.back ()?
Snow Bases
50

<button backButton>BACK</button>

Vous pouvez mettre cela dans une directive, qui peut être attachée à n'importe quel élément cliquable:

import { Directive, HostListener } from '@angular/core';
import { Location } from '@angular/common';

@Directive({
    selector: '[backButton]'
})
export class BackButtonDirective {
    constructor(private location: Location) { }

    @HostListener('click')
    onClick() {
        this.location.back();
    }
}

Usage:

<button backButton>BACK</button>
hansmaad
la source
c'est génial!
Rafael de Castro
1
Si vous actualisez sur cette page et cliquez sur le bouton qui déclenche "this.location.back ()", il déclenchera simplement une actualisation de page. Existe-t-il un moyen que le module de localisation puisse détecter si le chemin précédent existe?
Henry LowCZ
bon travail homme! ;)
elciospy
Gardez à l'esprit si un utilisateur est allé directement à une page où le bouton Retour existe et s'il clique sur un bouton .. alors il sera jeté de l'application à la page précédente en fonction de l'historique du navigateur (plate-forme).
hastrb
Pour les futurs lecteurs, consultez la documentation de l'API
hastrb le
24

Testé avec Angular 5.2.9

Si vous utilisez une ancre au lieu d'un bouton, vous devez en faire un lien passif avec href="javascript:void(0)"pour faire fonctionner Angular Location.

app.component.ts

import { Component } from '@angular/core';
import { Location } from '@angular/common';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {

  constructor( private location: Location ) { 
  }

  goBack() {
    // window.history.back();
    this.location.back();

    console.log( 'goBack()...' );
  }
}

app.component.html

<!-- anchor must be a passive link -->
<a href="javascript:void(0)" (click)="goBack()">
  <-Back
</a>
JavierFuentes
la source
Je suggère de créer une directive «clickPreventDefault» plutôt que de l'utiliser javascript:void(0). Quelque chose comme ... @Directive({ selector: '[clickPreventDefault]' }) export class ClickPreventDefaultDirective { @HostListener("click", ["$event"]) onClick($event: Event) { $event.preventDefault(); } }
bmd
Merci @bmd, c'est une manière plus élaborée mais ça marche aussi. Une autre solution de travail est de ne pas utiliser herf: <a (click)="goBack()"> bien que de cette façon, ne passez pas les validateurs HTML.
JavierFuentes
20

Vous pouvez implémenter une routerOnActivate()méthode sur votre classe d'itinéraire, elle fournira des informations sur l'itinéraire précédent.

routerOnActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction) : any

Ensuite, vous pouvez utiliser router.navigateByUrl() et transmettre les données générées à partir de ComponentInstruction. Par exemple:

this._router.navigateByUrl(prevInstruction.urlPath);
Sasxa
la source
Est-ce toujours valable pour Angular 2.1.0?
smartmouse
1
@smartmouse Je ne pense pas, il y a de la documentation pourrouterOnActivate
Bojan Kogoj
4
Le lien routerOnActivate () dans cette réponse est rompu. Il semble que ce ne soit pas la façon de procéder dans la version finale.
rmcsharry
14

Fonctionne également pour moi lorsque je dois revenir en arrière comme dans le système de fichiers. PS @angular: "^ 5.0.0"

<button type="button" class="btn btn-primary" routerLink="../">Back</button>
Shevtsiv Andriy
la source
7
J'espérais que cela fonctionnerait, mais cela revient à la route suivante au-dessus - pas à la route sur laquelle vous étiez avant de naviguer vers la page. Bon à savoir que cela existe, mais si vous avez plusieurs points d'entrée pour votre composant, cette méthode ne retournera que sur l'itinéraire au-dessus, pas d'où vous venez.
Scott Byers
Au moment où j'écris "quand j'ai besoin de reculer comme dans le système de fichiers" :) Pour moi, ce comportement était également inattendu.
Shevtsiv Andriy
12

J'ai créé un bouton que je peux réutiliser n'importe où sur mon application.

Créer ce composant

import { Location } from '@angular/common';
import { Component, Input } from '@angular/core';

@Component({
    selector: 'back-button',
    template: `<button mat-button (click)="goBack()" [color]="color">Back</button>`,
})
export class BackButtonComponent {
    @Input()color: string;

  constructor(private location: Location) { }

  goBack() {
    this.location.back();
  }
}

Ajoutez-le ensuite à n'importe quel modèle lorsque vous avez besoin d'un bouton de retour.

<back-button color="primary"></back-button>

Remarque: Il s'agit d'un matériau angulaire, si vous n'utilisez pas cette bibliothèque, supprimez le mat-buttonet color.

Todd Skelton
la source
Est-ce que cette approche fonctionne cependant avec les sorties de routeur nommées? Supposons que j'en ai plusieurs sur la page et que je ne souhaite revenir que sur l'un d'eux, est-ce que cela fonctionnerait?
rrd
Vous devrez utiliser une approche différente pour cette situation. Si vous aviez le même bouton arrière dans deux prises de routeur différentes, elles feront probablement la même chose et reviendront sur la dernière prise de routeur qui a été changée.
Todd Skelton, le
Pour les points de vente nommés, j'ai trouvé que cette approche fonctionnait: this.router.navigate (['../'], {relativeTo: this.route})
rrd
Comment utiliser ce composant dans un autre composant?
RN Kushwaha
12

Après toutes ces réponses impressionnantes, j'espère que ma réponse trouvera quelqu'un et l'aidera. J'ai écrit un petit service pour garder une trace de l'historique des itinéraires. Ça y est.

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

@Injectable()
export class RouteInterceptorService {
  private _previousUrl: string;
  private _currentUrl: string;
  private _routeHistory: string[];

  constructor(router: Router) {
    this._routeHistory = [];
    router.events
      .pipe(filter(event => event instanceof NavigationEnd))
      .subscribe((event: NavigationEnd) => {
        this._setURLs(event);
      });
  }

  private _setURLs(event: NavigationEnd): void {
    const tempUrl = this._currentUrl;
    this._previousUrl = tempUrl;
    this._currentUrl = event.urlAfterRedirects;
    this._routeHistory.push(event.urlAfterRedirects);
  }

  get previousUrl(): string {
    return this._previousUrl;
  }

  get currentUrl(): string {
    return this._currentUrl;
  }

  get routeHistory(): string[] {
    return this._routeHistory;
  }
}
Anjil Dhamala
la source
Après avoir essayé plus ou moins toutes les solutions, je trouve que c'est la façon la plus cohérente de le faire
A. D'Alfonso
Que se passe-t-il si j'ouvre la page sur un lien particulier et que je souhaite qu'il revienne à la page dans l'arborescence de la page?
Ivan
8

La façon dont je l'ai fait lors de la navigation vers une page différente, ajoutez un paramètre de requête en passant l'emplacement actuel

this.router.navigate(["user/edit"], { queryParams: { returnUrl: this.router.url }

Lisez ce paramètre de requête dans votre composant

this.router.queryParams.subscribe((params) => {
    this.returnUrl = params.returnUrl;
});

Si returnUrl est présent, activez le bouton de retour et lorsque l'utilisateur clique sur le bouton de retour

this.router.navigateByUrl(this.returnUrl); // Hint taken from Sasxa

Cela devrait pouvoir accéder à la page précédente. Au lieu d'utiliser location.back, je pense que la méthode ci-dessus est plus sûre, considérez le cas où l'utilisateur atterrit directement sur votre page et s'il appuie sur le bouton de retour avec location.back, il redirigera l'utilisateur vers la page précédente qui ne sera pas votre page Web.

Puneeth Rai
la source
Vous devez importer ActivatedRoute et l'utiliser à la place de Router sur l'abonnement queryParams (par exemple, this.route.queryParams.subscribe), mais sinon, cela semble fonctionner!
Stephen Kaiser
pour moi, cela fonctionne bien avec le routeur lui-même, même en angulaire 4
Puneeth Rai
1
Meilleure réponse, mais dans Angular 5 (jusqu'à x?), Vous devez injecter un objet "ActivatedRoute" et utiliser queryParams sur cet objet, comme Stephen Kaiser l'a déjà dit.
Satria
8

Dans RC4:

import {Location} from '@angular/common';
Tomasz Bielawa
la source
3

Pour revenir en arrière sans rafraîchir la page, on peut faire en html comme ci-dessous javascript: history.back ()

<a class="btn btn-danger" href="javascript:history.back()">Go Back</a>
Singhak
la source
Je recommanderais Locationplutôt d' utiliser le service. API officielle
hastrb
2

Depuis la bêta 18:

import {Location} from 'angular2/platform/common';

Albert
la source
2

Une autre solution

window.history.back();

Džan Operta
la source
Fonctionne pour moi location.back () fonctionne également mais pas je compile avec --prod
Alex