【问题标题】:Angular - get component instance in router eventsAngular - 在路由器事件中获取组件实例
【发布时间】:2020-07-27 20:15:23
【问题描述】:

我正在尝试为我的 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。我在这里错过了什么?

【问题讨论】:

  • 您可以使用<router-outlet (activate)="updateTitle(componentInstance)"event 来获取当前的组件实例 stackoverflow.com/questions/40294262/…
  • 我不能,因为我有多个 - 一个在另一个里面,等等。我不想去把(激活)所有这些。
  • 你不需要全部都去激活,你可以创建一个指令

标签: angular typescript angular-routing


【解决方案1】:

基于@yurzui 的想法,您可以为此使用指令:

激活组件.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.

【讨论】:

  • 由于某种原因,它在其他模块中不起作用。基本上,我有 AppModule/router-outlet => ChildModule/router-outlet 并且它适用于 AppModule 但不适用于后续出口......无法弄清楚为什么。该指令位于单独的模块中,因此在两个模块中都导入了。
  • 对不起,一切顺利!这是因为 CLI 没有接受模块更改。谢谢!
【解决方案2】:

有一点误会。当您 console.dir .component 时,您得到的不是 AboutComponent 的 instance,而是它的 class。 因此,如果您想以 component.title 的身份访问它,您的 getter 应该是静态的

static get title(): string {
  return "About the demo";
}

【讨论】:

  • 不知道为什么,但您无法从路由器逻辑中获取实例。如果您更喜欢component.prototype.title,也可以尝试将其作为您的问题解决方案
【解决方案3】:

使用@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 了解更多详情。

?如果你的路由器出口有名字,你可以将它传递给instance()方法并检索对应出口的组件。

【讨论】:

    猜你喜欢
    • 2017-05-29
    • 2018-01-07
    • 1970-01-01
    • 2020-05-12
    • 2017-08-21
    • 2018-01-28
    • 2016-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多