简体   繁体   English

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

[英]Angular - get component instance in router events

I'm trying to implement a title service for my angular 10 app.我正在尝试为我的 angular 10 应用程序实现标题服务。 I need to subscribe to router events, grab the activated route's component, see if it implements title() getter and then use it to set the page's title.我需要订阅路由事件,获取激活路由的组件,看看它是否实现了title() getter,然后用它来设置页面的标题。 Sounds easy...听起来很容易...

The code:编码:

    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;
      });

But the comp.title is ALWAYS undefined.comp.title始终未定义。 Even though the component does implement get title() getter:即使组件确实实现了get title() getter:

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

  ...
}

I see that console.dir outputs AboutComponent .我看到console.dir输出AboutComponent What am I missing here?我在这里想念什么?

Based on @yurzui's idea, you can use a directive for this:基于@yurzui 的想法,您可以为此使用指令:

activated-component.directive.ts激活组件.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标题.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 . ng-运行演示

there is a little misunderstanding.有一点误解。 when you console.dir the .component you get not an instance of AboutComponent but a class of it.当您 console.dir .component您得到的不是 AboutComponent 的实例,而是它的class thus your getter should be static if you want to access it as component.title因此,如果您想将它作为component.title访问,您的吸气剂应该是 static

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

With the @bespunky/angular-zen library you can do this:使用@bespunky/angular-zen库,您可以这样做:

In the template holding the router outlet:在包含路由器插座的模板中:

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

Then, in the component that needs access to the instance:然后,在需要访问实例的组件中:

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 )
    }
}

It is open-source and you can install the library like this:它是开源的,您可以像这样安装库:

npm install @bespunky/angular-zen npm 安装@bespunky/angular-zen

Here's a live example with more details. 这是一个包含更多详细信息的实时示例

If your router outlet has a name, you can pass it to the instance() method and retrieve the corresponding outlet's component.如果您的路由器插座有名称,您可以将其传递给instance()方法并检索相应插座的组件。

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

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