web-dev-qa-db-ja.com

Angular 2 Activatedroute paramsがサービス内または<router-outlet>の外で機能しない

非常に奇妙な問題があります:index.html

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

ナビゲーションメニューは、ナビゲーションメニューのコンポーネントです。ルーターアウトレットコンテンツには、「アセット」と呼ばれるコンポーネントがあります。

資産コンポーネントで私がしたこと:

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

これは機能し、ルートのパラメーター(一種の「asset /:id」)を取得します。

ナビゲーションメニューコンポーネント(ルーターアウトレットの「外側」)とcontextserviceと呼ばれるグローバルサービスで同じことを試しました。上記と同じコードですが、ルート変更でもトリガーされません。現在のルーターのスナップショットを取得しようとすると

  const strId = this.route.snapshot.params["id"];

navigationEndイベントがトリガーされた後も同じ結果になります。paramsは空のオブジェクトであるため、strIdは未定義です。

アセットコンポーネントでのみ機能します。これは意図したとおりに機能していますか?

私の意図は、すべてのroute(-params)の変更をリッスンしているグローバルサービス(またはnavメニューのような「グローバル」コンポーネント)からイベントをトリガーすることでした。

私の唯一の解決策は、NavigationEndイベントごとに完全なURLを解析することですが、これは適切ではありません...または各子コンポーネント(ルーターアウトレット)自体のparams変更を処理することです。

たぶん私は理解の基本的なエラーがあります...

ありがとう

受け入れられた答えからの解決策:

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

RoutesRecognizedをangular router !!からインポートすることを忘れないでください。

22
Cabe Skuriles

ルーターによって追加されたコンポーネントは、ルーターセグメント(ActivatedRoute)を渡しますが、サービスにはアクティブ化されたルートはありません。 router.eventsにサブスクライブし、ルートツリー(router.firstChild ... `)を走査して、必要な特定のルートシーケンスからパラメーターを取得できます。

こちらもご覧ください https://github.com/angular/angular/issues/1102

20

以下はangularのサービスです。

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

        }

1
Royi Namir

実際には、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を確認します。

1
LuizAsFight