订阅 Angular 2 中的路由参数和查询参数

问题描述 投票:0回答:10

我已经设置了以下路由系统

export const MyRoutes: Routes = [
  {path: '', redirectTo: 'new', pathMatch: 'full'},
  {path: ':type', component: MyComponent}
];

并拥有以下导航系统

goToPage('new');
goToPageNo('new', 2);

goToPage(type) {
  this.router.navigate([type]);
}
goToPageNo(type, pageNo) {
  this.router.navigate([type], {queryParams: {page: pageNo}});
}

示例URL看起来像这样

http://localhost:3000/new

http://localhost:3000/new?page=2

http://localhost:3000/更新

http://localhost:3000/updated?page=5

有时他们有可选查询参数(页面)

现在我需要读取 route params 和 queryParams

ngOnInit(): void {
  this.paramsSubscription = this.route.params.subscribe((param: any) => {
    this.type = param['type'];
    this.querySubscription = this.route.queryParams.subscribe((queryParam: any) => {
      this.page = queryParam['page'];
      if (this.page)
        this.goToPageNo(this.type, this.page);
      else
        this.goToPage(this.type);
    })
  })
}

ngOnDestroy(): void {
  this.paramsSubscription.unsubscribe();
  this.querySubscription.unsubscribe();
}

现在这没有按预期工作,访问没有 queryParams 的页面可以工作,然后我访问带有 queryParams 的页面“goToPageNo”被多次调用,因为我在路由参数内订阅了 queryParams。

我查看了 Angular 2 文档,他们没有任何示例或代码来同时实现对 route params 和 queryParams 的订阅。

有什么方法可以正确地做到这一点吗?有什么建议吗?

angular rxjs
10个回答
55
投票

我在订阅之前使用

Observable.combineLatest
组合可观察量,成功获得对 queryParams 和 Params 的单个订阅。

例如。

var obsComb = Observable.combineLatest(this.route.params, this.route.queryParams, 
  (params, qparams) => ({ params, qparams }));

obsComb.subscribe( ap => {
  console.log(ap.params['type']);
  console.log(ap.qparams['page']);
});

38
投票

对于 Angular 6+

import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';

...

combineLatest(this.route.params, this.route.queryParams)
    .pipe(map(results => ({params: results[0].xxx, query: results[1]})))
    .subscribe(results => {
        console.log(results);
    });

xxx
是从您的路线出发的地方

{path: 'post/:xxx', component: MyComponent},

Angular 12+(即 RxJs 版本 7+)的注意事项,使用:

import { combineLatest, map } from 'rxjs';

并将数组传递给

combineLatest
函数:

combineLatest([this.route.params, this.route.queryParams])
    .pipe(map(results => ({params: results[0].xxx, query: results[1]})))
    // ...

24
投票

迟到的答案,但另一个解决方案: 我没有订阅 params 和 queryparams,而是订阅了路由器上的 NavigationEnd 事件。仅触发一次,并且 params 和 queryparams 在快照上均可用:(角度 4 的示例)

this.router.events.filter(event=>event instanceof NavigationEnd)
   .subscribe(event=>{
       let yourparameter = this.activatedroute.snapshot.params.yourparameter;
       let yourqueryparameter = this.activatedroute.snapshot.queryParams.yourqueryparameter;
   });

关于取消订阅:是的,路由参数、查询参数或导航事件订阅会被路由器自动取消订阅,但有一个例外:如果您的路由有子路由,则在子路由之间导航时,不会发生取消订阅。仅当您导航离开父路线时!

例如我遇到过将选项卡作为子路线的情况。在第一个选项卡组件的构造函数中订阅路由参数以检索数据。每次我从第一个选项卡导航到第二个选项卡并返回时,都会添加另一个订阅,从而导致请求数量成倍增加。


14
投票

另一种方法(在 Angular 7+ 上)是订阅 ActivatedRoute url observable 并使用“withLatestFrom”来获取最新的 paramsMap 和 queryParamsMap。看来参数是在 url observable 发出之前设置的:

this.route.url.pipe(
  withLatestFrom(this.route.paramMap, this.route.queryParamMap)
).subscribe(([url, paramMap, queryParamMap]) => {
  // Do something with url, paramsMap and queryParamsMap
});

https://rxjs-dev.firebaseapp.com/api/operators/withLatestFrom

https://angular.io/api/router/ActivatedRoute


7
投票

根据 Shifatul 的回答,假设可观测值的工作同时发生变化,并且只触发一次:

import { combineLatest } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';

...

combineLatest(this.route.params, this.route.queryParams)
    .pipe(map(results => ({params: results[0].xxx, query: results[1]})), debounceTime(0))
    .subscribe(results => {
        console.log(results);
    });

5
投票

Shifatul 的回答延长了...

  • Angular 9+(使用数组进行 mergeLastest)和
  • 更简单的语法(使用打字稿数组参数分解):
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';

// ...

combineLatest([this.route.params, this.route.queryParams])
    .subscribe(([params, queryParams]) => {
        console.log("your route data:", params, queryParams);
    });

3
投票

使用

combineLatest
提出的解决方案无法正常工作。第一次路由更改后,每当
param
queryParam
值发生变化时,您都会收到一个事件,这意味着当一个更改而另一个未更改时,您会收到处于中间状态的呼叫,非常糟糕。

@rekna 的解决方案对我来说非常有效,除了我的应用程序首次加载时没有收到事件,所以这是我对 @rekna 解决方案的修改:

this.routeUpdate(this.activatedRoute.snapshot);
this.routeSubscription = this.router.events
  .pipe(filter(event => event instanceof NavigationEnd))
  .subscribe(event => this.routeUpdate(this.activatedRoute.snapshot));

其中

routeUpdate
是一种执行所需参数处理的方法。


1
投票

使用您的 ActivatedRouteSnapshot

 中的 
ActivatedRoute

ActivatedRouteSnapshot
接口有
params
queryParams
属性,可以同时获取这两个值。

constructor(private route: ActivatedRoute) {
    console.log(this.route.snapshot.params);
    console.log(this.route.snapshot.queryParams);
}

编辑:正如OP所述,我们只能通过这种技术获得参数的初始值。

示例Plunker


1
投票

我认为你应该使用 zip 运算符 https://www.learnrxjs.io/operators/combination/zip.html

因为如果您使用combineLatest并更改url参数或查询参数,您将获得新查询参数和旧url参数的值。

网址例如:

http://localhost/1?value=10

http://localhost/2?value=20

http://localhost/3?value=30


0
投票

这对我有用:

zip([this.route.params, route.queryParams]).subscribe(([params, queryParam]) => {}
© www.soinside.com 2019 - 2024. All rights reserved.