typescript Angular 2 Activatedroute 参数在服务中或 <router-outlet> 之外不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40375888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 03:59:25  来源:igfitidea点击:

Angular 2 Activatedroute params not working in Service or outside <router-outlet>

angulartypescriptroutingroutes

提问by Cabe Skuriles

I have a very strange problem: index.html

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

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

The navigation-menu is a component for the nav menu. In router-outlet content there is a component called "assets".

导航菜单是导航菜单的一个组件。在路由器出口内容中有一个称为“资产”的组件。

What I did in asset component:

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

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

This works and I get the parameters of my route (which is kind of "asset/:id).

这有效,我得到了我的路线的参数(这是一种“资产/:id”)。

Now I tried the same in my Navigation-Menu Component (which is "outside" the router outlet) and in a global service called contextservice. Same code as above, but it is not even triggered on route change. If I try to get a current router snapshot

现在我在我的导航菜单组件(它在路由器出口的“外部”)和一个名为 contextservice 的全局服务中尝试了同样的方法。与上面相同的代码,但它甚至不会在路由更改时触发。如果我尝试获取当前路由器快照

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

after NavigationEnd event was triggered it is the same result: strId is undefined because params are an empty object.

NavigationEnd 事件触发后,结果相同:strId 未定义,因为 params 是一个空对象。

It only works in my asset component. Is this working as intended or how should this be handled?

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

My intension was to trigger an event from a global service (or a "global" component like the nav menu) which is listening to all route(-params) changes.

我的意图是从监听所有路由(-params)更改的全局服务(或“全局”组件,如导航菜单)触发事件。

My only solution would be to parse the complete url after every NavigationEnd event which in my opinion is no proper way...Or to handle the params change in each child component (in router-outlet) itself.

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

Maybe I have just a basic error in understanding...

也许我在理解上有一个基本的错误......

Thanks

谢谢

Solution from accepted answer:

来自接受答案的解决方案:

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

Don't forget to import RoutesRecognized from angular router!!

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

采纳答案by Günter Z?chbauer

The component added by the router gets the router segment (ActivatedRoute) passed, but in a service there is no activated route. You can subscribe to router.events and traverse the routes tree (router.firstChild...`) to get params out of a specific route sequement you need.

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

See also https://github.com/angular/angular/issues/11023

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

回答by Royi Namir

Here is an angular service which does that :

这是一个 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());

        }

.

.

回答by LuizAsFight

Actually, your activatedRoute is correct and updated, but you have all the tree in that. so if you go all the way inside of route.firstChild, you will finally find the last route, which I called deeperActivatedRoute (inside of route.firstChild...route.firstChild)

实际上,您的 activateRoute 是正确的并且已更新,但是您拥有所有的树。所以如果你一直在 route.firstChild 里面,你最终会找到最后一条路线,我称之为 deepActivatedRoute(在 route.firstChild...route.firstChild 内部)

So what I did is create a service to track the deeperRoute, and have it always accessible

所以我所做的是创建一个服务来跟踪 deepRoute,并让它始终可以访问

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

Then in app.component.ts I start the service (just to ensure it's always tracking)

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

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

And finally, take your route wherever service you are:

最后,无论您身在何处,都可以选择您的路线:

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

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

Answering the question, you can just take the deeperActivatedRoute and check normally the snapshop.url, just as you would do in a component

回答这个问题,您可以使用 deepActivatedRoute 并正常检查 snapshop.url,就像您在组件中所做的一样

回答by Mark Odey

I have been browsing for a simple solution around the web and finally found something that works in angular 8.

我一直在网上浏览一个简单的解决方案,终于找到了一些适用于 angular 8 的方法。

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

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

This works as expected. There are many different flavors available over the web. However only this one worked for me. I am new to rxjs and observer piping so it gets quickly confusing when the chain gets long for me.

这按预期工作。网络上有许多不同的口味。然而,只有这个对我有用。我是 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!!!!
      });
  }
}

Obviously afterwards you can design your service however you want. To interface your params.

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