Як визначити URL-адресу попередньої сторінки в Angular?


101

Припустимо, я зараз перебуваю на сторінці, яка має URL-адресу /user/:id. Тепер із цієї сторінки я переходжу до наступної сторінки :id/posts.

Тепер чи є спосіб, щоб я міг перевірити, що таке попередня URL-адреса, тобто /user/:id.

Нижче мої маршрути

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

Відповіді:


80

Ви можете підписатися на зміни маршруту та зберегти поточну подію, щоб використовувати її, коли відбудеться наступна

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

Див. Також Як виявити зміну маршруту в Angular?


12
Дякую @ Günter Ти завжди рятуєш мій день.
Chandra Shekhar

29
Це не перелічує попередній маршрут для мене, лише поточний маршрут.
Девід Агірре,

2
Залежить від того, що ви очікуєте. Перший раз це nullтому, що немає попереднього маршруту. Це також потрібно зробити на кореневому маршрутизаторі, інакше ви отримаєте лише при переході між дочірніми маршрутами цього компонента.
Günter Zöchbauer

8
Це не дає попередньої URL-адреси, коли конструктор виконується вперше.
Ekaitz Hernandez Troyas

9
Яке значення ви очікуєте як попередня URL-адреса, коли конструктор запускається вперше?
Günter Zöchbauer

110

Можливо, всі інші відповіді стосуються кутових 2.Х.

Тепер це не працює для кутових 5.X. Я працюю з цим.

лише за допомогою NavigationEnd ви не можете отримати попередню URL-адресу.

оскільки маршрутизатор працює від "NavigationStart", "RoutesRecognized", ..., до "NavigationEnd".

Ви можете перевірити у

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

Але все-таки ви не можете отримати попередню URL-адресу навіть за допомогою "NavigationStart".

Тепер потрібно використовувати попарно.

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

За допомогою попарного ви можете побачити, що таке url від і до.

"RoutesRecognized" - це крок зміни від початкової до цільової URL-адреси.

отфільтруйте його та отримайте попередню URL-адресу.

Не в останню чергу,

помістіть цей код у батьківський компонент або вище (наприклад, app.component.ts)

оскільки цей код спрацьовує після завершення маршрутизації.

Оновіть кутовий 6+

events.filterДає помилку , тому що фільтр не є частиною подій, тому змінити код на

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
Реалізовано як послугу, і вона чудово працює. Я використовую angular 6.1.7.
A. El Idrissi

5
@ tjvg1991 Оновлення сторінки означає, що ви втратили дані пам'яті. якщо ви зберігаєте попередні дані, вам потрібно використовувати localStorage або cookie. (зберігайте дані у своїй місцевій пам’яті, а не в пам’яті)
BYUNGJU JIN

Я просто хочу вбити кнопку "Проголосувати" Дякую.
Мухаммед Умайр

@BYUNGJUJIN Дякую за це!
Джон

@ BYUNGJU JIN дякую, працює для мене. як отримати значення param за посиланням для переадресації, скажімо, наприклад, події [0]. urlAfterRedirects дає мені '/ inventoryDetails; test = 0; id = 45', я хочу отримати з цього значення id. Як я можу обійтися без використання subString.
JNPW

49

Створіть ін’єкційну службу:

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

Тоді використовуйте його скрізь, де вам потрібно. Щоб якомога швидше зберегти поточну змінну, необхідно скористатися послугою в 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
Я думаю, що це найелегантніше рішення. Спробуйте об'єднати цей код з новим фільтром і парним рішенням: stackoverflow.com/a/35287471/518879
danger89

2
Ps. Не забудьте додати цей RouterExtService до apps-routing.module.ts (у моєму випадку), @NgModule({ ..., providers: [RouterExtService]}) export class AppRoutingModule { }
приблизно

Добре, є велика проблема з цим рішенням служби .. У моєму випадку я викликаю routerExtService.getPreviousUrl()метод у конструкторі служби, що використовується в компоненті. З якоїсь причини це викликано раніше, ніж фактичне оновлення. Це означає, що ми маємо залежність від часу! Я думаю, що набагато простіше використовувати тему.
danger89

Ну, у мене це добре працювало в невеликому проекті. Можливо, для цього потрібна якась настройка відповідно до ваших потреб. Ви вирішили проблему?
Джуліано

В даний час я використовую так звані параметри матриці URL-адреси для «зберігання» мого стану в моїй URL-адресі, за замовчуванням URL-адреса браузера зберігає стан зараз, коли використовується кнопка «Назад». 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 })
небезпека89

20

Оновлений код Angular 6 для отримання попередньої URL-адреси у вигляді рядка.

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

Це повертає URL-адресу, яку заблокував охоронець, чи є спосіб отримати лише попередню URL-адресу, яка була активована (не заблокована охоронцем)?
Exocomp

1
Будь-яка підказка щодо найкращого способу скасування підписки на маршрутизатор, який можна спостерігати?
j4v1

Працює! Я насправді не знаю, чому "NavigationEnd" не працює
davidwillianx

13

Це працювало для мене у кутових> = 6.x версіях:

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

10

Я використовую Angular 8 і відповідь @ franklin-pious вирішує проблему. У моєму випадку отримання попередньої URL-адреси всередині підписки викликає деякі побічні ефекти, якщо вона додається з деякими даними у поданні.

Обхідним шляхом, яким я скористався, було надсилання попередньої URL-адреси як необов’язкового параметра в навігації маршрутом.

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

І щоб отримати це значення в компоненті:

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

this.router та this.route вводяться всередину конструктора кожного компонента та імпортуються як @ angular / маршрутизатори.

import { Router, ActivatedRoute }   from '@angular/router';

10

Angular 8 & rxjs 6 у версії 2019 року

Я хотів би поділитися рішенням, заснованим на інших чудових рішеннях.

Спочатку зробіть службу для прослуховування змін маршрутів і збережіть останній попередній маршрут у темі поведінки, потім надайте цю послугу в головному app.component у конструкторі, а потім використовуйте цю службу, щоб отримати попередній маршрут, який ви хочете, коли завгодно.

випадок використання: ви хочете перенаправити користувача на сторінку реклами, а потім автоматично перенаправити його туди, звідки він прийшов, тому вам потрібен останній попередній маршрут.

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

  }
}

надати послугу в app.module

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

Введіть його в app.component

  constructor(
    private routeEventsService: RouteEventsService
  )

нарешті, використайте збережений попередній маршрут у потрібному вам компоненті

  onSkipHandler(){
    // navigate the user to where he did came from
    this.router.navigate([this.routeEventsService.previousRoutePath.value]);
  }

Це працює дуже добре. Але у мене є швидке запитання. Ви коли-небудь відписуєтесь?
w0ns88

додати take (1) так -> попарно (), take (1)). підписатися ((e: any)
Мукус

1
Зверніть увагу, що якщо ви користуєтесь @Injectable({ providedIn: 'root' })послугою, вона автоматично завантажується в кореневий модуль (AppModule) проекту, і, отже, вам не потрібно вручати її в app.module. Детальніше див. У документації . Не потрібно відмовлятися від маршрутизатора Observables, як зазначено у цій відповіді
Hkidd

5

ДО КУТНІХ 7+

Насправді, починаючи з Angular 7.2, немає необхідності користуватися послугою для збереження попередньої URL-адреси. Ви можете просто використовувати об'єкт стану, щоб встановити останню URL-адресу перед посиланням на сторінку входу. Ось приклад для сценарію входу.

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

Крім того, ви також можете передати дані в шаблоні:

@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 також ви можете зберегти його в місцевому сховищі, але я не вважаю це за краще) краще економити в сервісі та отримувати це значення звідти

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

3

Ви можете використовувати Location, як згадано тут .

Ось мій код, якщо посилання відкрилося на новій вкладці

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

Необхідний імпорт

import { Router } from '@angular/router';
import { Location } from '@angular/common';

0

Досить просто за допомогою previousNavigationоб'єкта:

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

0

Я мав певні труднощі, щоб отримати доступ до попередньої URL-адреси всередині охорони.
Без реалізації спеціального рішення, це працює для мене.

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

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

Початковою URL-адресою буде попередня сторінка URL-адреси.


-2

Усі вищезазначені ВІДПОВІДІ завантажуватимуться URL-адреси кілька разів. Якщо користувач також відвідав будь-який інший компонент, цей код завантажиться.

Так що краще використовувати, концепція створення служби. https://community.wia.io/d/22-access-the-previous-route-in-your-angular-5-app

Це буде добре працювати у всіх версіях Angular. (будь ласка, не забудьте додати його до масиву провайдерів у вашому файлі app.module!)


-2

Використовуючи попарно від rxjx, ви можете досягти цього простіше. імпортувати {filter, попарно} з 'rxjs / operator';

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

У мене була подібна проблема, коли я хотів повернутися на попередню сторінку. Рішення було простішим, ніж я міг собі уявити.

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

І вона повертається до батьківської URL-адреси. Сподіваюся, це комусь допоможе;)


Це не буде працювати, ви говорите, щоб піднятись по маршруту маршрутизатора, а не за попередньою URL-адресою, як зазначено в OP.
Фредерік Єсід Пенья Санчес,

Це не працює, якщо ваша URL-адреса складна з параметрами або не має того самого шляху, що і батьківський. Це працює, лише якщо ви хочете повернутися з "щось / батько / дитина" у "щось / батько".
А. Ель Ідріссі,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.