Angular 2 Activatedroute参数无法在服务中或在<router-outlet>

时间:2016-11-02 08:59:59

标签: angular typescript routing routes

我有一个非常奇怪的问题: 的index.html

<navigation-menu *ngIf="isLoggedIn"></navigation-menu>
<div class="content-wrapper" [ngClass]="{'fullContent' : !isLoggedIn}">
    <section class="content">
        <router-outlet></router-outlet>            
    </section>
</div>

导航菜单是导航菜单的组件。 在路由器插座内容中有一个名为&#34; assets&#34;的组件。

我在资产组件中做了什么:

import { ActivatedRoute}from "@angular/router";
constructor(private route: ActivatedRoute){}
public ngOnInit(): void {
    this.route.params.subscribe(params => {
        const id = params["id"];
}

这有效,我得到了我的路线参数(有点&#34; asset /:id)。

现在我在导航菜单组件(在#34;外部&#34;路由器插座)和名为contextservice的全局服务中尝试了相同的操作。 与上面的代码相同,但在路由更改时甚至没有触发。如果我尝试获取当前路由器快照

  const strId = this.route.snapshot.params["id"];
触发NavigationEnd事件后,结果相同:strId未定义,因为params是一个空对象。

它仅适用于我的资产组件。 这是按预期工作还是应该如何处理?

我的意图是从全局服务(或者像导航菜单这样的&#34;全局&#34;组件)触发事件,该事件正在监听所有路径(-params)更改。

我唯一的解决方案是在每个NavigationEnd事件之后解析完整的URL,在我看来这是不正确的方法......或者处理每个子组件(在路由器插座中)的params更改。

也许我在理解中只有一个基本错误......

由于

接受答案的解决方案:

this.router.events.subscribe(val => {
        if (val instanceof RoutesRecognized) {
            var strId = val.state.root.firstChild.params["id"];
        }});

不要忘记从角度路由器导入RoutesRecognized !!

4 个答案:

答案 0 :(得分:19)

路由器添加的组件获取路由器段(ActivatedRoute),但在服务中没有激活路由。您可以订阅router.events并遍历路由树(router.firstChild ...`)以获取您需要的特定路由分段的参数。

另见https://github.com/angular/angular/issues/11023

答案 1 :(得分:1)

这是一个有角度的服务:

import {Injectable}                                                        from '@angular/core';
import {ActivatedRoute, NavigationEnd, NavigationExtras, ParamMap, Router} from "@angular/router";
import {RouterExtensions}                                                  from "nativescript-angular/router";
import {NavigationOptions}                                                 from "nativescript-angular/router/ns-location-strategy";
import {Observable}                                                        from "rxjs/Observable";
import {first}                                                             from "rxjs/operators/first";
import {filter}                                                            from "rxjs/operators/filter";
import {map}                                                               from "rxjs/operators/map";
import {switchMap}                                                         from "rxjs/operators/switchMap";
import {unRegisterAndroidOnBack}                                           from "../../utils/view.utils";

@Injectable()
export class RoutingService
    {
        constructor(private routerExtensions: RouterExtensions, private route: ActivatedRoute, private router: Router)
        {
        }
        public getActivatedRouteParameter(paramName: string): Observable<ParamMap>
        {
            return this.router.events.pipe(filter(e => e instanceof NavigationEnd),
                                           map((): ActivatedRoute =>
                                               {
                                                   let route = this.route;
                                                   while (route.firstChild)
                                                       {
                                                           route = route.firstChild;
                                                       }
                                                   return route;
                                               }),
                                           filter((route: ActivatedRoute) => route.outlet === 'primary'),
                                           switchMap((route: ActivatedRoute) => route.paramMap) , first());

        }

.

答案 2 :(得分:1)

实际上,您的activatedRoute是正确的并且已更新,但是您拥有其中的所有树。因此,如果您一路走到route.firstChild内部,您将最终找到最后一条路线,我将其称为deeperActivatedRoute(在route.firstChild ... route.firstChild内部)

所以我要做的是创建一个服务来跟踪deeperRoute,并使其始终可访问

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

@Injectable()
export class ActivatedRouteService {
  private _deeperActivatedRoute: ActivatedRoute;
  get deeperActivatedRoute(): ActivatedRoute {
    return this._deeperActivatedRoute;
  }

  constructor(private router: Router, private route: ActivatedRoute) {}

  init(): void {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        // Traverse the active route tree
        let activatedChild = this.route.firstChild;
        if (activatedChild != null) {
          let nextActivatedChild;
          while (nextActivatedChild != null) {
            nextActivatedChild = activatedChild.firstChild;
            if (nextActivatedChild != null) {
              activatedChild = activatedChild.firstChild;
            }
          }
        }

        this._deeperActivatedRoute = activatedChild || this.route;
      }
    });
  }
}

然后在app.component.ts中启动服务(只是为了确保它始终处于跟踪状态)

export class AppComponent {
  constructor(private activatedRouteService: ActivatedRouteService) {
    this.activatedRouteService.init();
  }
}

最后,无论您身在何处,都要走自己的路线:

export class ForbiddenInterceptor implements HttpInterceptor {
  constructor(private activatedRouteService: ActivatedRouteService) { }

  doYourStuff(): void {
       //you'll have the correct activatedRoute here
       this.activatedRouteService.deeperActivatedRoute;
  }
}

回答问题,您只需采取deeperActivatedRoute并正常检查snapshop.url,就像在组件中一样

答案 3 :(得分:1)

我一直在浏览一个简单的网络解决方案,终于找到了可以在angular 8中工作的东西。

https://medium.com/@eng.ohadb/how-to-get-route-path-parameters-in-an-angular-service-1965afe1470e

这按预期工作。网上有许多不同的口味。但是,只有这个为我工作。我是rxjs和观察者管道系统的新手,所以当链对我来说很长时,它很快就会造成混乱。

export class MyParamsAwareService {
  constructor(private router: Router) { 
    this.router.events
      .pipe(
        filter(e => (e instanceof ActivationEnd) && (Object.keys(e.snapshot.params).length > 0)),
        map(e => e instanceof ActivationEnd ? e.snapshot.params : {})
      )
      .subscribe(params => {
      console.log(params);
      // Do whatever you want here!!!!
      });
  }
}

显然,之后,您可以根据需要设计服务。连接参数。