Angular - 在路由器事件中获取组件实例

Angular - get component instance in router events

我正在尝试为我的 angular 10 应用实施标题服务。我需要订阅路由器事件,获取激活路由的组件,查看它是否实现了 title() getter 然后用它来设置页面的标题。听起来很简单...

代码:

    this.router.events
      .pipe(
        filter((event) => event instanceof NavigationEnd),
        map(() => this.rootRoute(this.route)),
        filter((route: ActivatedRoute) => route.outlet === "primary"),
        filter(
          (route: ActivatedRoute) =>
            ComponentWithTitleBase.isPrototypeOf(route.component as any)
        ),
        map((route) => (route.component as unknown) as ComponentWithTitleBase),
        tap(console.dir)
      )
      .subscribe((comp: ComponentWithTitleBase) => {
        this.titleSvc.title = comp.title;
      });

但是 comp.title 始终未定义。即使该组件确实实现了 get title() getter:

export class AboutComponent extends ComponentWithTitleBase implements OnInit {
  get title(): string {
    return "About the demo";
  }

  ...
}

我看到 console.dir 输出 AboutComponent。我在这里错过了什么?

有点误会。当您 console.dir .component 时,您得到的不是 AboutComponent 的 实例 ,而是它的 class。 因此,如果您想以 component.title

的形式访问它,您的 getter 应该是静态的
static get title(): string {
  return "About the demo";
}

根据@yurzui 的想法,您可以为此使用一个指令:

激活-component.directive.ts

@Directive({
  selector: 'router-outlet'
})
export class ActivatedComponentsDirective {

  constructor(r: RouterOutlet, titleService: TitleService) {
    r.activateEvents.pipe(
      // takeUntil(r.destroyed),
    ).subscribe(compInstance => compInstance.title && titleService.newTitle(compInstance.title))
  }

  ngOnDestroy () {
    // destroyed.next;
    // destroyed.complete();
  }
}

title.service.ts

@Injectable({
  providedIn: 'root'
})
export class TitleService {

  private src = new Subject<string>();

  newTitle (t: string) {
    this.src.next(t);
  }

  constructor() { this.initConsumer() }

  private initConsumer () {
    this.src.pipe(
      /* ... */
    ).subscribe(title => {
      console.log('new title', title);
    })
  }
}

ng-run demo.

使用 @bespunky/angular-zen 库,您可以这样做:

在包含路由器插座的模板中:

<router-outlet publishComponent></router-outlet>

然后,在需要访问实例的组件中:

import { Component     } from '@angular/core';
import { NavigationEnd } from '@angular/router';
import { RouteAware    } from '@bespunky/angular-zen/router-x';

@Component({
    selector   : 'app-demo',
    templateUrl: './demo.component.html',
    styleUrls  : ['./demo.component.css']
})
export class DemoComponent extends RouteAware
{
    protected onNavigationEnd(event: NavigationEnd): void
    {
        const currentInstance = this.componentBus.instance();

        console.log(`Navigation ended. Current component instance:`, currentInstance )
    }
}

它是开源的,你可以像这样安装库:

npm install @bespunky/angular-zen

Here's a live example 更多详情。

If your router outlet has a name, you can pass it to the instance() method and retrieve the corresponding outlet's component.