简体   繁体   English

在 Angular2 中订阅 router.events.subscribe 时如何从 Route 或 ActivatedRoute 获取数据?

[英]How to get data from Route or ActivatedRoute when subscribing to router.events.subscribe in Angular2?

I'm trying to get the data from a Router whenever the Route changes but I'm not having success.每当路由发生变化时,我都试图从路由器获取数据,但我没有成功。 Here I set the asdf property在这里我设置了asdf属性

@NgModule({
  bootstrap: [AppComponent],
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent,
    OverviewComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot([
      { path: '', pathMatch: 'full', redirectTo: '' },
      { component: LoginComponent, path: 'login' },
      {
        children: [
          { path: '', pathMatch: 'full', redirectTo: 'overview', data: { asdf: 'hello' } },
          { component: OverviewComponent, path: 'overview', data: { asdf: 'hello' } },
        ], component: DashboardComponent,
        path: '',
      },
    ]),
  ],
})
export class AppModule { }

And here I can get the URL from the router when the route changes but asdf is undefined :(在这里,当路由更改但未定义asdf时,我可以从路由器获取 URL :(

import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ActivatedRoute, NavigationEnd } from '@angular/router';
@Component({
  selector: 'cs-map',
  styleUrls: ['map.component.css'],
  templateUrl: 'map.component.html',
})
export class MapComponent implements OnInit {
  private routerSub;

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

  public ngOnInit() {
    this.router.events.subscribe((val) => {
      if (val instanceof NavigationEnd) {
        let url = val.url;
        console.log(this.activatedRoute.snapshot.data['asdf']); // data is defined but asdf is not :(
      }
    });
  }
}

How can I get asdf 's value?我怎样才能获得asdf的价值?

Edit: I'm navigating to /overview编辑:我导航到/overview

Something like this:像这样的东西:

constructor(private router: Router, 
        private activatedRoute: ActivatedRoute)
{

 this.router.events
        .filter(event => event instanceof NavigationEnd)
        .map(() => this.activatedRoute)
        .map(route => route.firstChild)
        .switchMap(route => route.data)
        .map(data => data['asdf'])
}
  1. For every events from router, I filter only NavigationEnd event对于来自路由器的每个事件,我只过滤 NavigationEnd 事件
  2. Then I map this event to the activatedRoute (because I want to read the value of activatedRoute on NavigationEnd).然后我将此事件映射到激活的路由(因为我想读取 NavigationEnd 上的激活路由的值)。
  3. I map the activatedRoute to the firstChild (first children declared with RouterModule.forRoot()).我将activatedRoute 映射到firstChild(用RouterModule.forRoot() 声明的第一个子节点)。
  4. Then a switchMap is made to get the data of this route, a switchMap because data is an observable.然后做了一个switchMap来获取这条路由的数据,一个switchMap,因为data是一个observable。
  5. Finally I map the data object to the key I want, in this case asdf最后我将数据对象映射到我想要的键,在这种情况下为 asdf

The following is updated to work with rxjs v6以下已更新以与 rxjs v6 一起使用

constructor(private router: Router, 
        private activatedRoute: ActivatedRoute)
{

   this.router.events
        .pipe(
         filter(event => event instanceof NavigationEnd),
         map(() => this.activatedRoute),
         map(route => route.firstChild),
         switchMap(route => route.data),
         map(data => data['asdf']))
}

Here is a modified example using @Neelavar link example.这是使用@Neelavar链接示例的修改示例。

It might look long but it's simple, be patient, if you stick through it, it should work.它可能看起来很长,但很简单,要有耐心,如果你坚持下去,它应该会奏效。 Just following the steps outlined should take a few minutes.只需按照概述的步骤操作即可花费几分钟时间。

Full Explanation for my setup, for beginners我的设置的完整说明,适合初学者

You should already know how to create components and setup routing, I won't explain that in depth.您应该已经知道如何创建组件和设置路由,我不会深入解释。

1. Setup Data Property in Routes Array 1.在路由数组中设置数据属性

In your routes array (you will find this either in app.module.ts or app-routes.module.ts or in some cases a routes.ts file).在你的路由数组中(你会在app.module.tsapp-routes.module.ts或在某些情况下在routes.ts文件中找到它)。

If you can't find this, check basic routing setup in:如果找不到,请在以下位置检查基本路由设置:

a basic setup is all you need!一个基本的设置就是你所需要的!

Add the data property like so (you will need to generate the home component):像这样添加 data 属性(您需要生成 home 组件):

export const routes: Routes = [
  { path: 'home', component: HomeComponent, data: {title: 'home'} },
  { path: '', pathMatch: 'full', redirectTo: '/home' },
];

2. Create a class 2.创建一个类

RouteData.ts , I have it in the same folder space as app.module.ts RouteData.ts ,我将它放在与app.module.ts相同的文件夹空间中

export class RouteData {
  title: string;
}

This is just to add types for using the observable in typescript, the IDE can then autocomplete "title" or "id" or "animation" for me if I add that to the data class later.这只是添加类型以在打字稿中使用 observable,如果我稍后将其添加到数据类中,IDE 可以为我自动完成“标题”“id”“动画”

3. Import the following into app.component.ts 3. 将以下内容导入 app.component.ts

import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { filter, map, switchMap } from 'rxjs/operators';
import { RouteData } from './route-data';

Then above the constructor code, declare the variable然后在构造函数代码上面,声明变量

routeData$: Observable<RouteData>;

Then inside the constructor然后在构造函数里面

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

4. Then inside constructor again 4.然后再次构造函数中

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
  ) {

    this.routeData$ = router.events.pipe(
      filter(routeEvent => routeEvent instanceof NavigationEnd),
      map(() => activatedRoute),
      map(activatedRoute => activatedRoute.firstChild),
      switchMap(firstChild => firstChild.data),
      map((data: RouteData) => data)
      );

  }

Explanation of code adapted from @Tuizi link Example Comment:改编自@Tuizi链接的代码说明示例评论:

  • For every event from router, filter only for the NavigationEnd event (when the router has completed navigation) .对于来自路由器的每个事件,仅过滤NavigationEnd事件(当路由器完成导航时)

  • Then map (return) the currently activatedRoute.然后映射(返回)当前激活的路由。

  • Map the activatedRoute to the firstChild (The first child of this route in the router state tree).将activatedRoute 映射到firstChild(路由器状态树中该路由的第一个子节点)。

  • Then a switchMap emits the data of this route, use a switchMap because each "data" that is emitted is an observable, the switch map will cancel the old observable when a new one is emitted, saving memory.然后一个 switchMap 发出这条路由的数据,使用 switchMap 因为发出的每个“数据”都是一个 observable,当一个新的 observable 发出时,switch map 会取消旧的 observable,节省内存。

  • Map (return) the data object, assign it a type of RouteData.映射(返回)数据对象,为其分配一个 RouteData 类型。

  • Finally you can use this Observable in a template using async pipe最后,您可以使用异步管道在模板中使用此 Observable

    <span *ngIf="routeData$ | async as routeData">
        {{ routeData.title | titlecase }}
      </span>

*A note: "async as" breaks type checking in the template at the moment :( *注意:“async as”目前会破坏模板中的类型检查:(

github issue github问题

If you are hitting the route the first time you load the route in your browser, ActivatedRoute will have the current data.如果您是第一次在浏览器中加载路线时点击路线,ActivatedRoute 将拥有当前数据。 But if you then click on something which causes a second router navigation, the ActivatedRoute instance for that second route will have the original route's information.但是,如果您随后单击导致第二个路由导航的内容,则该第二个路由的 ActivatedRoute 实例将具有原始路由的信息。 This could be due to to the fact that it was the ActivatedRoute at the time it was injected into the constructor.这可能是因为它在注入构造函数时是 ActivatedRoute。

However there is an updated instance of ActivatedRouteSnapshot associated with the ActivationEnd event, so you can access the data like this:但是,有一个与 ActivationEnd 事件关联的 ActivatedRouteSnapshot 的更新实例,因此您可以像这样访问数据:

this.router.events.pipe(
    filter(event => event instanceof ActivationEnd),
    map(event => (<ActivationEnd>event).snapshot),
    map(snapshot => (<ActivatedRouteSnapshot>snapshot).data)).subscribe(data => {
        console.log('data from the NEW route: ' + data);
    });

data in the routes must be an array of objects rather than just object so define them like this路由中的数据必须是一个对象数组而不仅仅是对象,所以像这样定义它们

{ component: LoginComponent, path: 'login', data:[{myKey1: myValue1}] },

Now to retrieve it use this code in your components constructor现在要检索它,请在组件构造函数中使用此代码

constructor(private router:Router, private activeRoute:ActivatedRoute) {

  router.events
    .filter(event => event instanceof NavigationEnd)
    .map(_ => this.router.routerState.root)
    .map(route => {
      while (route.firstChild) route = route.firstChild;
      return route;
    })
  .flatMap(route => route.data)
  .subscribe(data => {
    console.log(data[0].myKey1);

    });

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM