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

Posted

技术标签:

【中文标题】Angular 2 Activatedroute 参数在服务中或 <router-outlet> 之外不起作用【英文标题】:Angular 2 Activatedroute params not working in Service or outside <router-outlet> 【发布时间】:2017-03-15 12:37:17 【问题描述】:

我有一个很奇怪的问题: 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  ActivatedRoutefrom "@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 事件触发后,结果相同:strId 未定义,因为 params 是一个空对象。

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

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

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

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

谢谢

接受答案的解决方案:

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

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

【问题讨论】:

谢谢。从接受的答案中的大量阅读来看,有几种方法可以跟踪有效路线的变化,但我最终以您所做的相同解决方案(使用 RoutesRecognized)结束,因为它更具可读性并且为您提供与更复杂的相同级别的详细信息解决方案。 【参考方案1】:

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

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

【讨论】:

这是我一直在寻找的。更新问题 这正是我想要的!就我而言,它不是服务而是组件。该组件不是路由的一部分,也不是路由的子组件。答案中的解决方案效果很好。【参考方案2】:

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

        

.

【讨论】:

【参考方案3】:

我一直在网上浏览一个简单的解决方案,终于找到了适用于 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!!!!
      );
  

显然,之后您可以随心所欲地设计您的服务。接口你的参数。

【讨论】:

【参考方案4】:

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

所以我所做的是创建一个服务来跟踪 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;
      
    );
  

然后在 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;
  

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

【讨论】:

以上是关于Angular 2 Activatedroute 参数在服务中或 <router-outlet> 之外不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 4 - 失败:无法解析 ActivatedRoute 的所有参数:(?, ?, ?, ?, ?, ?, ?, ?)

Angular 测试,为不同的测试用例动态改变 ActivatedRoute 参数

用ActivatedRoute获取url中的参数

使用 Angular 2 Http 从 REST Web 服务获取数据

将路由参数传递给组件

(Angular)从子级销毁父级订阅