Angular 2路由器事件第一次没有开火?

时间:2017-04-05 16:58:08

标签: angular angular2-routing

我从一个组件路由到另一个组件。路线完成后,我想使用上一条路线的URL。我已将下面的代码放入要路由到的组件的构造函数中,但它不会在第一个路径上触发。在第一个路径之后,该功能每次都会触发。

this.router.events
      .filter(e => e instanceof NavigationEnd)
      .pairwise().subscribe((e) => {
          console.log(e);
    });

如果我删除成对功能,它似乎在第一条路线上触发,但它只列出当前路线,而不是前一路线。

 router.events
  .filter(e => e instanceof NavigationEnd)
  .subscribe(e => {
    console.log(e);
 });

我的目标是在新组件路由到时检索上一个路由。我在这做错了什么?

8 个答案:

答案 0 :(得分:6)

我看到所有这些解决方案都将中继到route.snapshot,并尝试将NavigationEnd操作与其结合起来。但是,如果您尝试访问该页面-NavigationEnd的第一个router.events不会触发该页面。快照也会触发父路由,而不是子路由。所以首先您可以使用子路由,但也不会像第一个那样触发它。

this.router.events.pipe(
  filter((event) => event instanceof NavigationEnd),
  map(() => this.aRoute.snapshot),
  map((route) => {
    while (route.firstChild) {
      route = route.firstChild;
    }
    return route;
  })
)

因此,对我来说,在当前路径上优先正确的最佳解决方案是使用router.events + router.url,且类型为NavigationEnd

 this.router.events
   .pipe(
      filter((event) => event instanceof NavigationEnd),
      startWith(this.router)
   )
   .subscribe((event: NavigationEnd) => {
     // there will be first router.url - and next - router events
 })

答案 1 :(得分:5)

我有完全相同的场景,我发现it's too late在子组件的构造函数中使用pairwise订阅NavigationEnd。

您可以订阅根组件中的路由器,并通过以下示例的服务共享路由数据:

events.service.ts

import { Injectable } from '@angular/core';
import { RouteChanged } from '../models/route-changed.model';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class EventsService {
  public routeChanged = new BehaviorSubject<RouteChanged>({ prevRoute: '/', currentRoute: '/' });

  constructor() {
  }
}

app.component.ts(您的根组件)

...

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
    private subscriptions = new Subscription();

    constructor(private eventsService: EventsService) {
            this.subscriptions.add(this.router.events
                .filter(event => event instanceof NavigationEnd)
                .pairwise()
                .subscribe(navigationEvents => {
                    const prevPage = <NavigationEnd>navigationEvents[0];
                    const currentPage = <NavigationEnd>navigationEvents[1];
                    this.eventsService.routeChanged.next(
                        { prevRoute: prevPage.urlAfterRedirects, currentRoute: currentPage.urlAfterRedirects });
                }));
        }

    ngOnDestroy(): void {
        this.subscriptions.unsubscribe();
    }

    ...
}

您的目标-route.ts

...
constructor(private eventsService: EventsService) {
    this.subscriptions.add(this.eventsService.routeChanged.subscribe((routeChanged) => {
        // use routeChanged.prevRoute and routeChanged.currentRoute here...
    }));
}

P.S。在服务中使用BehaviorSubjectReplaySubject以便在页面加载后子组件订阅时获取正确的先前路由事件非常重要。

答案 2 :(得分:4)

已经给出了答案:当组件为其注册时,已经引发了NavigationEnd事件。我不喜欢“Dimitar Tachev”的想法,通过在主题中代理这些事件来创建一种解决方法。 就我而言,解决方案是:

  1. 让Component像以前一样订阅NavigationEnd事件。
  2. 使组件从ngOnInit方法中注入的Route对象加载初始状态。
  3. 最后,另一个解决方案是将订阅路由更改事件移动到组件的构造函数中。

答案 3 :(得分:2)

pairwise在第二个及以后的排放量(http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwise)中排放

因此设置初始值很重要,例如:

this.router.events
  .startWith(new NavigationEnd(0, '/', '/'))
  .filter(e => e instanceof NavigationEnd)
  .pairwise()
  .subscribe((e) => {
      console.log(e);
  });

答案 4 :(得分:2)

原因是导航事件发生时您的组件尚不存在。

创建一个在app.component.ts中注入的全局服务,并将其也注入您的组件中。

在服务上创建“助手”可观察对象。

// RouterEventsService.ts 
navigationStart$ = this.router.events.pipe(filter((e): e is NavigationStart => e instanceof NavigationStart));
navigationEnd$ = this.router.events.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd));

navigationEndReplay$ = this.navigationEnd$.pipe(shareReplay(1));

在用于服务的构造函数中,您必须预订navigationEndReplay$事件。这意味着以后您可以在组件中订阅它并获取缓存的最新结束事件。

// RouterEventsService.ts constructor
this.routerEvents.navigationEndReplay$.subscribe();   // note: unsubscribe in app.component not needed

然后,您可以在组件中使用routerEvents.navigationEndReplay$,并且在初始化组件后立即触发。您可以在构造函数ngOnInitngAfterContentInit等中使用它。

最好保持navigationEnd$navigationEndReplay$的明确。

答案 5 :(得分:0)

2019年,这仍然是一个问题

这是在子组件中获取所有路由更改(包括页面加载路由)的方法。

  constructor(
    private router: Router, 
    private route: ActivatedRoute
  ) {
    // First route event on load
    this.setFromSnapshot(this.route.snapshot);
    // Subsequent events after load
    this.router.events
      .pipe(filter(event => event instanceof ActivationStart))
      .subscribe(event => this.setFromSnapshot(event.snapshot));
  }

  setFromSnapshot(snapshot) {
    // Do something
  }

答案 6 :(得分:0)

受先前答案的启发,我提出了以下解决方案:

  import { filter, map, startWith } from 'rxjs/operators';

  constructor(
    private router: Router, 
    private route: ActivatedRoute
  ) {
    this.router.events
      .pipe(
        filter(event => event instanceof ActivationStart),
        map(({ snapshot }) => snapshot),
        startWith(this.route.snapshot)
      )
      .subscribe((snapshot: ActivatedRouteSnapshot) => /** ... do something */ )
  }

答案 7 :(得分:-1)

我偶然发现了同样的问题并找到了原因:订阅路由器事件的服务从未由依赖注入者实例化,因为该服务未在该路由注入。

服务似乎只是在某处注入时才会实现。

因此,如果要调用整个代码(而不是事件),请检查您的第一条路线。

相关问题