Cómo volver a la última página

370

¿Hay alguna forma inteligente de volver a la última página en Angular 2?

Algo como

this._router.navigate(LASTPAGE);

Por ejemplo, la página C tiene un Go Backbotón,

  • Página A -> Página C, haga clic en ella, regrese a la página A.

  • Página B -> Página C, haga clic en ella, vuelva a la página B.

¿El enrutador tiene esta información de historial?

Hongbo Miao
fuente

Respuestas:

673

En realidad, puede aprovechar el servicio de ubicación integrado, que posee una API "Atrás".

Aquí (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();
  }
}

Editar : como se menciona en @ charith.arumapperuma, Locationdebe importarse de @angular/commonmodo que la import {Location} from '@angular/common';línea sea importante.

Amir Sasson
fuente
75
La ubicación debe importarse desde "angular2 / router" en versiones anteriores de Angular 2. En versiones más recientes, debe ser desde "@ angular / common".
charith.arumapperuma
2
Si lo tiene integrado en el marco, no veo ninguna razón para usar el "nativo" "window.history.back ();" que es una función HTML5 ( developer.mozilla.org/en-US/docs/Web/API/Window/history )
Amir Sasson
77
Para lo que vale, la documentación oficial de la API de Angular2 para los Locationestados: "Nota: es mejor usar el servicio de enrutador para activar los cambios de ruta. Use la ubicación solo si necesita interactuar o crear URL normalizadas fuera del enrutamiento". La respuesta de @ Sasxa aparentemente muestra una forma de usar Routerpara hacer esto. Sin embargo, el Locationmétodo definitivamente es más conveniente. ¿Alguien sabe por qué el Routermétodo podría ser más correcto que el Locationmétodo?
Andrew Willems
2
@ Andrew: He encontrado el problema, que no puedes retroceder dos veces, si usas this.location.back (). Volverás al sitio inicial.
Johannes
1
@ yt61, no estoy seguro, ¿quizás reutilización? o si puede acceder a una página específica desde varias rutas, por lo que no sabe de antemano la ruta a la que volver.
Amir Sasson
111

En la versión final de Angular 2.x / 4.x: aquí están los documentos 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
fuente
1
Mientras navegamos de regreso a la pantalla anterior, podemos retener los valores ingresados ​​sin usar un objeto en servicio.
Vignesh
¿Cómo mostrar la animación mientras se ejecuta location.back ()?
Bases de nieve
49

<button backButton>BACK</button>

Puede poner esto en una directiva, que se puede adjuntar a cualquier elemento en el que se pueda hacer clic:

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

Uso:

<button backButton>BACK</button>
Hansmaad
fuente
¡Eso es genial!
Rafael de Castro el
1
Si actualiza en esta página y hace clic en el botón que activa "this.location.back ()", solo activará una actualización de la página. ¿Hay alguna forma de que el módulo de ubicación pueda detectar si existe una ruta anterior?
Henry LowCZ
buen trabajo hombre! ;)
elciospy
Tenga en cuenta que si un usuario fue directamente a una página donde existe el botón Atrás y si hace clic en un botón ... será expulsado de la aplicación a la página anterior de acuerdo con el historial del navegador (plataforma).
hastrb
Para futuros lectores, mire los documentos API
hastrb
24

Probado con Angular 5.2.9

Si utiliza un ancla en lugar de un botón, usted debe hacer un enlace pasiva con href="javascript:void(0)"hacer el trabajo Localización angular.

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
fuente
Sugeriría crear una directiva 'clickPreventDefault' en lugar de usarla javascript:void(0). Algo así como ... @Directive({ selector: '[clickPreventDefault]' }) export class ClickPreventDefaultDirective { @HostListener("click", ["$event"]) onClick($event: Event) { $event.preventDefault(); } }
bmd
Gracias @bmd, es una forma más elaborada pero también funciona. Otra solución de trabajo es no usar herf: <a (clic) ="goBack()"> aunque de esta manera no pase Validadores HTML.
JavierFuentes
20

Puede implementar el routerOnActivate()método en su clase de ruta, proporcionará información sobre la ruta anterior.

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

Luego puede usar router.navigateByUrl()y pasar datos generados desde ComponentInstruction. Por ejemplo:

this._router.navigateByUrl(prevInstruction.urlPath);
Sasxa
fuente
¿Sigue siendo válido para Angular 2.1.0?
smartmouse
1
@smartmouse No lo creo, hay documentación pararouterOnActivate
Bojan Kogoj
44
El enlace routerOnActivate () en esta respuesta está roto. Parece que esta no es la forma de hacerlo en la versión de lanzamiento.
rmcsharry
14

También funciona para mí cuando necesito retroceder como en el sistema de archivos. PS @angular: "^ 5.0.0"

<button type="button" class="btn btn-primary" routerLink="../">Back</button>
Shevtsiv Andriy
fuente
77
Tenía la esperanza de que esto funcionaría, pero esto regresa a la siguiente ruta por encima, no a la ruta en la que estaba antes de navegar a la página. Es bueno saber que esto existe, pero si tiene múltiples puntos de entrada para su componente, este método solo volverá a la ruta por encima, no desde donde se originó.
Scott Byers
Mientras escribo "cuando necesito retroceder como en el sistema de archivos" :) Para mí, este comportamiento también fue inesperado.
Shevtsiv Andriy
12

Hice un botón que puedo reutilizar en cualquier lugar de mi aplicación.

Crea este componente

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

Luego agréguelo a cualquier plantilla cuando necesite un botón de retroceso.

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

Nota: Esto está usando material angular, si no está usando esa biblioteca, elimine el mat-buttony color.

Todd Skelton
fuente
¿Este enfoque funciona con salidas de enrutadores con nombre? Digamos que tengo varios en la página y solo quiero volver a uno de ellos, ¿funcionaría?
rrd
Tendrás que usar un enfoque diferente para esa situación. Si tenía el mismo botón de retroceso en dos salidas de enrutador diferentes, probablemente ambos harán lo mismo y volverán a la última salida de enrutador que se cambió.
Todd Skelton
Para los puntos de venta con nombre, descubrí que este enfoque funcionaba: this.router.navigate (['../'], {relativeTo: this.route})
rrd
¿Cómo usar este componente dentro de otro componente?
RN Kushwaha
12

Después de todas estas increíbles respuestas, espero que mi respuesta encuentre a alguien y lo ayude. Escribí un pequeño servicio para hacer un seguimiento del historial de rutas. Aquí va.

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
fuente
Después de intentar más o menos todas las soluciones, creo que esta es la forma más consistente de hacerlo
A. D'Alfonso
¿Qué sucede si abro la página en un enlace en particular y quiero que vuelva a la página que está en el árbol de páginas?
Ivan
8

La forma en que lo hice mientras navegaba a una página diferente agrega un parámetro de consulta pasando la ubicación actual

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

Lea este parámetro de consulta en su componente

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

Si returnUrl está presente, active el botón Atrás y cuando el usuario haga clic en el botón Atrás

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

Esto debería poder navegar a la página anterior. En lugar de usar location.back, creo que el método anterior es más seguro, considere el caso en el que el usuario accede directamente a su página y si presiona el botón Atrás con location.back, lo redirigirá al usuario a la página anterior, que no será su página web.

Puneeth Rai
fuente
Necesita importar ActivatedRoute y usarlo en lugar de Router en la suscripción de queryParams (por ejemplo, this.route.queryParams.subscribe), pero de lo contrario, parece funcionar.
Stephen Kaiser
para mí está funcionando bien con el enrutador incluso en angular 4
Puneeth Rai
1
La mejor respuesta, pero en Angular 5 (¿hasta x?) Necesita inyectar un objeto de "ActivatedRoute" y usar queryParams en este objeto, como ya lo dijo Stephen Kaiser.
Satria
8

En RC4:

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

Para regresar sin actualizar la página, podemos hacerlo en html como javascript a continuación : history.back ()

<a class="btn btn-danger" href="javascript:history.back()">Go Back</a>
Singhak
fuente
Recomendaría usar el Locationservicio en su lugar. API oficial
hastrb
2

Desde beta 18:

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

Albert
fuente
2

Otra solución

window.history.back();

Džan Operta
fuente
Funciona para mí location.back () también funciona pero no compilo con --prod
Alex