Como voltar à última página

369

Existe uma maneira inteligente de voltar a última página no Angular 2?

Algo como

this._router.navigate(LASTPAGE);

Por exemplo, a página C tem um Go Backbotão,

  • Página A -> Página C, clique nela, retorne à página A.

  • Página B -> Página C, clique nela, retorne à página B.

O roteador possui essas informações de histórico?

Hongbo Miao
fonte

Respostas:

672

Na verdade, você pode aproveitar o serviço de localização interno, que possui uma API "Voltar".

Aqui (em 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 : Como mencionado por @ charith.arumapperuma Locationdeve ser importado de, @angular/commonpara que a import {Location} from '@angular/common';linha seja importante.

Amir Sasson
fonte
75
O local deve ser importado do "angular2 / router" em versões mais antigas do Angular 2. Nas versões mais recentes, deve ser de "@ angular / common".
Charith.arumapperuma
2
Se você o incorporou no framework, não vejo motivo para usar o "nativo" "window.history.back ();" que é um recurso do HTML5 ( developer.mozilla.org/pt-BR/docs/Web/API/Window/history )
Amir Sasson
7
Quanto vale a pena, a documentação oficial da API do Angular2 para os Locationestados: "Nota: é melhor usar o serviço Router para acionar alterações de rota. Use Location apenas se precisar interagir ou criar URLs normalizados fora do roteamento". A resposta de @ Sasxa aparentemente mostra uma maneira de usar Routerisso. No entanto, o Locationmétodo definitivamente é mais conveniente. Alguém sabe por que o Routermétodo pode ser mais correto que o Locationmétodo?
Andrew Willems
2
@ Andrew: Eu encontrei o problema, que você não pode voltar duas vezes, se você usar this.location.back (). Você retornará ao site inicial.
Johannes
11
@ yt61, não tenho certeza, talvez reutilização? ou se você puder acessar uma página especificada a partir de várias rotas, para que não saiba com antecedência a rota para a qual voltar.
Amir Sasson
111

Na versão final do Angular 2.x / 4.x - veja os 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
fonte
11
Ao navegar de volta à tela anterior, podemos reter os valores inseridos sem usar um objeto em serviço.
Vignesh
Como mostrar a animação enquanto o location.back () está em execução?
Snow Bases
48

<button backButton>BACK</button>

Você pode colocar isso em uma diretiva, que pode ser anexada a qualquer elemento clicável:

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
fonte
Fantástico!
Rafael de Castro
11
Se você atualizar nesta página e clicar no botão que aciona "this.location.back ()", ele apenas acionará uma atualização da página. Existe alguma maneira de o módulo Location detectar se existe um caminho anterior?
Henry LowCZ
bom trabalho cara! ;)
elciospy 21/01
Lembre-se de que se um usuário foi diretamente para uma página onde o botão Voltar existe e se ele clica em um botão, ele será expulso do aplicativo para a página anterior, de acordo com o histórico do navegador (plataforma).
hastrb 24/04
Para futuros leitores, consulte os documentos da API
hastrb
24

Testado com Angular 5.2.9

Se você usar uma âncora em vez de um botão, você deve torná-lo uma ligação passiva com href="javascript:void(0)"a tornar o trabalho Localização 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
fonte
Eu sugeriria a criação de uma diretiva 'clickPreventDefault' em vez de usar javascript:void(0). Algo como ... @Directive({ selector: '[clickPreventDefault]' }) export class ClickPreventDefaultDirective { @HostListener("click", ["$event"]) onClick($event: Event) { $event.preventDefault(); } }
DMO
Obrigado @bmd, é uma maneira mais elaborada, mas também funciona. Outra solução de trabalho é não usar herf: <a (click)="goBack()">), embora desta forma não passe nos Validadores HTML.
JavierFuentes 12/04
20

Você pode implementar o routerOnActivate()método na sua classe de rota, ela fornecerá informações sobre a rota anterior.

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

Então você pode usar router.navigateByUrl()e transmitir dados gerados a partir de ComponentInstruction. Por exemplo:

this._router.navigateByUrl(prevInstruction.urlPath);
Sasxa
fonte
Isso ainda é válido para o Angular 2.1.0?
precisa
11
@smartmouse Acho que não, existe documentação pararouterOnActivate
Bojan Kogoj
4
O link routerOnActivate () nesta resposta está quebrado. Parece que não é esse o caminho na versão de lançamento.
Rmcsharry
14

Também funciona para mim quando preciso voltar como no sistema de arquivos. PS @ retangular: "^ 5.0.0"

<button type="button" class="btn btn-primary" routerLink="../">Back</button>
Shevtsiv Andriy
fonte
7
Eu esperava que isso funcionasse, mas isso volta para a próxima rota acima dela - não para a rota em que você estava antes de navegar para a página. É bom saber que isso existe, mas se você tiver vários pontos de entrada para o seu componente, esse método só voltará à rota acima dele, não de onde você se originou.
Scott Byers
Enquanto escrevo "quando preciso voltar como no sistema de arquivos" :) Para mim, esse comportamento também foi inesperado.
Shevtsiv Andriy
12

Eu criei um botão para reutilizar em qualquer lugar do meu aplicativo.

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

Em seguida, adicione-o a qualquer modelo quando precisar de um botão Voltar.

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

Nota: Isso está usando material angular, se você não estiver usando essa biblioteca, remova o mat-buttone color.

Todd Skelton
fonte
Essa abordagem funciona com tomadas de roteador nomeadas? Digamos que eu tenha vários na página e só queira voltar para um deles, isso funcionaria?
Rd
Você precisará usar uma abordagem diferente para essa situação. Se você tivesse o mesmo botão Voltar em duas tomadas diferentes de roteador, elas provavelmente farão a mesma coisa e voltarão à última tomada do roteador que foi alterada.
Todd Skelton
Para pontos de venda nomeados, descobri que essa abordagem funcionava: this.router.navigate (['../'], {relativeTo: this.route})
rrd
Como usar este componente dentro de outro componente?
RN Kushwaha 29/05/19
12

Depois de todas essas respostas impressionantes, espero que minha resposta encontre alguém e os ajude. Escrevi um pequeno serviço para acompanhar o histórico de rotas. Aqui vai.

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
fonte
Depois de tentar mais ou menos todas as soluções, acho que essa é a maneira mais consistente de fazer isso
A. D'Alfonso
E se eu abrir a página em um link específico e desejar que ela volte para a página na árvore de páginas?
Ivan
8

A maneira como fiz isso enquanto navegava para uma página diferente adiciona um parâmetro de consulta passando a localização atual

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

Leia este parâmetro de consulta no seu componente

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

Se returnUrl estiver presente, ative o botão voltar e quando o usuário clicar no botão voltar

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

Isso deve ser capaz de navegar para a página anterior. Em vez de usar location.back, sinto que o método acima é mais seguro, considere o caso em que o usuário acessa diretamente sua página e se ele pressionar o botão voltar com location.back, ele redirecionará o usuário para a página anterior, que não será sua página da web.

Puneeth Rai
fonte
É necessário importar o ActivatedRoute e usá-lo em vez do roteador na assinatura queryParams (por exemplo, this.route.queryParams.subscribe), mas, caso contrário, parece funcionar!
Stephen Kaiser
para mim ele está funcionando bem com o próprio roteador mesmo em angular 4
Puneeth Rai
11
Melhor resposta, mas no Angular 5 (até x?) Você precisa injetar um objeto "ActivatedRoute" e usar queryParams nesse objeto, como Stephen Kaiser já declarou.
Satria
8

No RC4:

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

Para voltar sem atualizar a página, podemos fazer em html, como abaixo javascript: history.back ()

<a class="btn btn-danger" href="javascript:history.back()">Go Back</a>
Singhak
fonte
Eu recomendaria usar o Locationserviço. API oficial
hastrb
2

Desde o beta 18:

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

Albert
fonte
2

Outra solução

window.history.back();

Džan Operta
fonte
Funciona para mim location.back () também funciona, mas não eu compilo com --prod
Alex