Search code examples
angulartypescriptangular-routing

Angular - get component instance in router events


I'm trying to implement a title service for my angular 10 app. 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. 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. Even though the component does implement get title() getter:

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

  ...
}

I see that console.dir outputs AboutComponent. What am I missing here?


Solution

  • Based on @yurzui's idea, you can use a directive for this:

    activated-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.