1
votes

Angular - obtenir une instance de composant dans les événements de routeur

J'essaie de mettre en œuvre un service de titre pour mon application angular 10. Je dois m'abonner aux événements du routeur, saisir le composant de la route activée, voir s'il implémente le getter title() , puis l'utiliser pour définir le titre de la page. Cela semble facile ...

Le code:

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

  ...
}

Mais le comp.title est TOUJOURS indéfini. Même si le composant implémente le getter get title() :

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

Je vois que console.dir génère AboutComponent . Qu'est-ce que j'oublie ici?


3 commentaires

Vous pouvez utiliser l'événement <router-outlet (activate)="updateTitle(componentInstance)" afin d'obtenir l' instance actuelle du composant stackoverflow.com/questions/40294262/...


Je ne peux pas parce que j'en ai plusieurs - un dans un autre, etc. Je ne veux pas aller les mettre (activer) tous.


Vous n'avez pas besoin d'aller les activer tous, vous pouvez créer une directive


3 Réponses :


0
votes

il y a un petit malentendu. lorsque vous console.dir le .component vous n'obtenez pas une instance de AboutComponent mais une classe de celui-ci. ainsi votre getter devrait être statique si vous voulez y accéder en tant que component.title

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


1 commentaires

Je ne sais pas pourquoi, mais vous ne pouvez pas obtenir une instance de la logique du routeur. vous pouvez également essayer component.prototype.title comme solution au problème si vous l'aimez plus



1
votes

Sur la base de l'idée de @ yurzui, vous pouvez utiliser une directive pour cela:

enabled-component.directive.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);
    })
  }
}

title.service.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();
  }
}

démo ng-run .


2 commentaires

Pour une raison quelconque, cela ne fonctionne pas dans un autre module. Fondamentalement, j'ai AppModule / router-outlet => ChildModule / router-outlet et cela fonctionne pour AppModule mais pas pour les points de vente suivants ... Je ne comprends pas pourquoi. La directive est dans un module séparé, elle est donc importée dans les deux.


désolé, tout va bien! c'était à cause de la CLI ne prenant pas les changements de module. Merci!



0
votes

Avec la bibliothèque @ bespunky / angular-zen , vous pouvez faire ceci:

Dans le modèle contenant la prise du routeur:

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

Ensuite, dans le composant qui a besoin d'accéder à l'instance:

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

Il est open-source et vous pouvez installer la bibliothèque comme ceci:

npm installer @ bespunky / angular-zen

Voici un exemple en direct avec plus de détails.

ðŸ'¡ Si la prise de votre routeur a un nom, vous pouvez le transmettre à la méthode instance() et récupérer le composant de la prise correspondante.


0 commentaires