如何确定Angular中的上一页URL?


99

假设我当前在具有URL的页面上/user/:id。现在,从此页面导航到下一页:id/posts

现在有一种方法,这样我就可以检查以前的URL是什么/user/:id

以下是我的路线

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

Answers:


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

27
这不会为我列出以前的路线,只有当前路线。
David Aguirre

2
取决于您的期望。第一次是null因为没有先前的路线。您还需要在根路由器上执行此操作,否则,只有在该组件的子路由之间导航时才会获得此权限。
君特Zöchbauer

8
首次执行构造函数时,不会提供先前的url。
Ekaitz Hernandez Troyas'7

9
首次执行构造函数时,您希望将哪个值用作上一个url?
君特Zöchbauer

107

也许所有其他答案都是针对角度2.X。

现在它不适用于Angular5.X。我正在使用它。

仅使用NavigationEnd,就无法获取以前的URL。

因为路由器的工作方式是从“ NavigationStart”,“ RoutesRecognized”等到“ NavigationEnd”。

您可以检查

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

但是,即使使用“ NavigationStart”,您仍然无法获得以前的URL。

现在您需要成对使用。

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”是从原始网址到目标网址的更改步骤。

因此,对其进行过滤并从中获取以前的网址。

最后但并非最不重要的,

将此代码放在父组件或更高版本中(例如,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
作为服务实施,效果很好。我正在使用角度6.1.7。
A. El Idrissi '18 -10-4

5
@ tjvg1991刷新页面表示您丢失了内存数据。如果保留以前的数据,则需要使用localStorage或cookie。(将数据保存在本地内存中)
BYUNGJU JIN

我只想杀死Upvote按钮,谢谢。
Muhammad Umair

@BYUNGJUJIN谢谢你!
约翰

@ BYUNGJU JIN谢谢你为我工作。我如何从重定向链接获取参数值,例如说events [0] .urlAfterRedirects给我'/ inventoryDe​​tails; 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
危险的

2
附言 不要忘了将此RouterExtService添加到apps-routing.module.ts中(以我@NgModule({ ..., providers: [RouterExtService]}) export class AppRoutingModule { }
为例

好的,此服务解决方案存在一个大问题。在我的情况下,我routerExtService.getPreviousUrl()在组件中使用的服务的构造函数中调用该方法。由于某种原因,此调用早于实际更新。意味着我们有时间依赖性!我认为使用Subject更容易。
危险89年

好吧,在一个小项目中,对我来说效果很好。可能需要进行一些调整以满足您的需求。你解决了这个问题吗?
朱利诺

我目前正在使用所谓的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);
              }
            });

11

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)-> pairwise(),take(1))。subscribe((e:any)
Mukus

1
请注意,如果您使用@Injectable({ providedIn: 'root' })该服务,则该服务会自动加载到项目的根模块(AppModule)中,因此您不必手动将其提供给app.module。有关详细信息,请参阅文档。不必取消对此应答中
Hkidd

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 / router成员导入。

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

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

1

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

初始网址将是上一个网址页面。



-2

使用rxjx中的pairwise可以更轻松地实现。从'rxjs / operators'导入{filter,pairwise};

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。我希望它可以帮助某人;)


这是行不通的,您要告诉路由器的路径,而不是OP指出的先前的URL。
Frederic YesidPeñaSánchez18年

如果您的网址包含参数,或者与父路径不相同,则此方法将无效。仅当您想从“某物/父母/孩子”返回到“某物/父母”时,它才有效。
A. El Idrissi '18 -10-4
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.