在Angular 2中检索params和queryParams的最佳实践

16

我正在尝试理解如何创建带有URL参数信息的路由。

这是我的路由(app.routes.ts):

{path: 'results/:id', component: MyResultsComponent},

以下是我导航到该路由的方式:

goToResultsPage(query: string) {
this.router.navigate(['results', query], { queryParams: { pageSize: 20 } });}

你可以看到,我还有一个查询参数。我在想,最好和最干净的方法是如何在我的MyResultsComponent中检索它。现在我有一种嵌套的subscribe结构:

ngOnInit() {
    this.route
      .params
      .subscribe(params => {
        this.query = params['id'];
        this.route
          .queryParams
          .subscribe(queryParams => {
            this.offset = queryParams['pageSize'];
            #find entries this.entryService.findEntries(this.query, this.pageSize);
      });
    });
  }

之后,我想将这些参数传递给我的EntryService,它将返回找到的条目。

6个回答

22

Observable.combineLatest在这种情况下是一个解决方案,不是吗?

Observable
  .combineLatest(
    this.route.params,
    this.route.queryParams,
    (params: any, queryParams: any) => {
      return {
        id: +params.id,
        pageSize: queryParams.pageSize ? +queryParams.pageSize: null
      }
    })
  .subscribe(bothParams => {
    this.id = bothParams.id;
    this.pageSize = bothParams.pageSize;
  });

感谢分享...对于路由参数和查询参数的情况,完美运作! - David Chelliah
3
从'aaa/:bbb?ccc=10'到'aaa/:bb',发生了两次重定向。 - L Y E S - C H I O U K H

9

我想如果您需要同时访问两者,那么快照是更好的选择。

没有经过测试(只是从我的头脑中想到的)

ngOnInit() {
    this.route
      .params
      .subscribe(params => {
        this.query = params['id'];
        this.offset = this.route.snapshot.queryParams['pageSize'];
        # find entries this.entryService.findEntries(this.query, this.pageSize);
      });
    });
  }

4
测试过并且对我有效。这是其他答案中最简单的解决方案。 - Halil
当params保持不变而queryParam发生更改时,这将失败。 - Nishanth Subramanya

3
使用forkJoin怎么样?
ForkJoin允许您合并两个可观测对象并等待它们的响应。您可以在此处查看文档,并在此处了解更多信息。
至于您的代码,它看起来像这样:
ngOnInit() {
    Observable.forkJoin(this.route.params, this.route.queryParams).subscribe(bothParams => {
        // bothParams is an array, on the first index we have the router.params 
        // on the second index we have the queryParams
        this.query = bothParams[0].query;
        this.pageSize = bothParams[0].pageSize;
        this.entryService.findEntries(this.query, this.pageSize);
    });
  }

您可能需要添加导入项:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';

4
如果其他人遇到了subscribe没有触发的情况,那是因为所有的可观察对象在之前都必须要完成,不能悬而未决。你需要在forkJoinsubscribe之前使用.take(1).first()方法。 - Scott Byers
1
@ScottByers 但是这样你肯定不能导航到另一个页面并重用此路由了吧? - Simon_Weaver
1
正确;但这是使forkJoin完成的唯一方法。您可以轻松地在同一流上编写另一个订阅以继续响应更改并再次执行完整的forkJoin调用。像这样的Observables在订阅之前都是冷的,因此您可以多次执行它。 - Scott Byers

2

我最近遇到这个困境,我找到了最适合我的需求的最佳解决方案,那就是使用Observable.merge

如果您想在同一组件中从参数paramsqueryParams中监听更改(例如带有过滤器的搜索),那么使用快照snapshot是不好的。

Observable.forkJoin的局限性是必须触发两个observable才能工作,如果您有一个场景,在参数或查询参数中可能会有更改,但不一定是同时,那么forkJoin将无法帮助您。

另一方面,Observable.merge会在任何一个observable被触发时都会被触发。当然,这也有一些缺点,因为您可能会在开始时使用params和queryParams调用两个回调函数。

以下是一个示例:

Observable.merge(
  this.route.params.map(params => this.handleParams(params)),
  this.route.queryParams.map(queryParams => this.handleQueryParams(queryParams))
)
.subscribe(
  () => this.onParamsOrQueryParamsChange()
);

3
Observable.combineLatest怎么样?请看我的回答。 - w1z

0
你可以尝试这个:
setTimeout(() => {
  this.route.queryParams
    .subscribe((params: Params) => {
      console.log('PARAMS',params);
      }
    });
},0);

0

2023

但对某些人来说,这仍然可能是一场斗争。

我发现实际上在你的 app.component 中做以下操作:

this._router.events.pipe(startWith(this._router)).subscribe((event) => {
    let queryparams;
    let url; 
    if (event instanceof ActivationEnd) {
        queryparams = event.snapshot.queryparams;
    }
    if (event instanceof NavigationEnd) {
        SomeService.routevent.next({url:event.url,queryparams:queryparams});
    }
});

创建一个服务并给它一个BehaviorSubject路由事件。然后无论在哪个组件或位置,您都可以获取最新的URL或查询参数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接