【问题标题】:Subscribe to both route params and queryParams in Angular 2在 Angular 2 中订阅路由参数和查询参数
【发布时间】:2017-04-03 14:41:16
【问题描述】:

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

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

示例网址如下所示

http://localhost:3000/新

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

http://localhost:3000/更新

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

有时他们有可选 queryParams(页面)

现在我需要同时阅读 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 文档,他们没有任何示例或代码同时实现对 路由参数和 queryParams 的订阅。

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

【问题讨论】:

    标签: angular rxjs


    【解决方案1】:

    使用您的ActivatedRoute 中的ActivatedRouteSnapshot

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

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

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

    例如Plunker

    【讨论】:

    • 不适用于多个链接:plnkr.co/edit/BQRbI5CrPNglvSB6NR2r
    • 如果你 zip 两者都发出,你只会在它们都发出时执行 onNext,这就是为什么 combineLatest 将是更好的运算符选择。
    • 如果我们尝试使用不同的路由参数重新加载当前路由,快照将不会更新...
    【解决方案2】:

    通过在订阅前使用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']);
    });
    

    【讨论】:

    • 哇,它有效,太棒了,非常感谢。顺便问一下,我们不需要在 ngOnDestroy() 函数中“取消订阅”这个吗?
    • 它实际上有什么帮助?如果我同时更改查询和路径参数,我的回调会被触发两次。
    • 从 'rxjs/Observable' 导入 { Observable };导入'rxjs/add/observable/combineLatest';
    • @joycollector 有什么解决办法吗?我坚持相同
    • @ShabbirDhangot 我还遇到了一个问题,即路由参数和片段上的 combineLatest 在导航时发出两个值。我通过 debounceTime(1) 传递 combineLatest 可观察对象来解决它。
    【解决方案3】:

    迟到的答案,但另一种解决方案: 我没有订阅 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;
       });
    

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

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

    【讨论】:

    • 这适用于paramqueryParam 更改的情况 - 如果两者都更改,则仅触发一次。很好的答案?
    【解决方案4】:

    对于 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},

    【讨论】:

    【解决方案5】:

    我认为你应该使用 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

    【讨论】:

      【解决方案6】:

      另一种方法(在 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

      【讨论】:

      • 非常感谢。这里有一半的人不理解有时需要 queryParams 有时只需要 params 的基本问题。
      【解决方案7】:

      使用combineLatest 的建议解决方案无法正常工作。在第一次路由更改后,每次paramqueryParam 值更改时都会收到一个事件,这意味着当一个更改而另一个没有更改时,您会收到一个中间状态的调用,非常糟糕。

      @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 是一种方法,可以进行所需的任何参数处理。

      【讨论】:

        【解决方案8】:

        Shifatul 的回答延长了 ...

        • Angular 9+(为 combineLastest 使用数组)和
        • 更简单的语法(使用 typescript 数组参数分解):
        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);
            });
        

        【讨论】:

          【解决方案9】:

          按照 Shifatul 的回答,这假设为同时更改的 observables 工作并且只触发一次:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-07-27
            • 2017-07-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-07
            • 2018-12-28
            • 1970-01-01
            相关资源
            最近更新 更多