Pesquisa de site

typescript - Como posso obter a hierarquia de visualização do Angular a partir de uma diretiva?


Versão 6+ do Angular

Estou trabalhando em uma diretiva que pode ser colocada em qualquer elemento para fins de registro de uso geral. Para contexto, seria algo como o seguinte:

@Directive({
  selector: '[log]'
})
export class LogDirective {
  @Input() log: string; // the log message
  @Input() logOn: string; // event name to trigger logging

  constructor(private renderer: Renderer2,
              private elementRef: ElementRef) {
  }

  ngOnInit() {
    this.renderer.listen(this.elementRef.nativeElement, this.logOn, () => {
      // log the message, etc.
    }
  }
}
<div log="Clicked the element" logOn="click">Click Me</div>

Isso funciona bem, mas eu pensei que seria interessante obter automaticamente algum tipo de hierarquia de elementos pais para que isso pudesse ser registrado. Dessa forma, alguém poderia olhar o log e ver de maneira bem fácil de onde isso foi registrado. Algo como "AppComponent -> SomeOtherComponent -> ParentComponent". Existe algo que possa ser injetado nesta diretiva que consiga determinar onde ela está na hierarquia de visualização?

Resposta #1

você pode injetar ViewContainerRef na diretiva para obter acesso ao componente que a hospeda. você pode então usar isso para ler tanto o componente atual quanto o componente pai desse componente.

Fazer isso de forma recursiva vai te dar o resultado que você está procurando.

algo assim (vou deixar o algoritmo de recursão para você):

constructor(private viewContainerRef: ViewContainerRef) { }

private clicked() {
    console.log(this.viewContainerRef['_view'].component);
    console.log(this.viewContainerRef['_view'].parent.component);
    console.log(this.viewContainerRef['_view'].parent.parent.component);
  }

(1) Demonstração Stackblitz

(1)ignore o restante do aplicativo aí, eu pesquisei no Google por um "template de diretiva Angular" de alguém e o mudei para conseguir isso rapidamente

(2)claro, aviso, "você não deve ler _attributes no Angular porque ele pode ser alterado sem aviso em versões futuras e você não terá suporte para isso" etc, etc etc..

Resposta #2

De acordo com a especificação da web para elementos DOM personalizados. O nome da tag deve conter um hífen, e isso atua como um separador de namespace. Isso é necessário para proteger seus componentes da web para que eles não entrem em conflito com futuras alterações do HTML.

Portanto, qualquer elemento DOM pai que tenha um hífen é um componente. Assumindo que todos os elementos personalizados sejam componentes Angular e que seu projeto Angular use um prefixo conforme as diretrizes.

Você poderia usar uma função como esta para gerar o prefixo.

function getPrefix() {
    let el = this.elementRef.native;
    let names = [];
    while (el) {
        if(el.tagName.indexOf("-") !== -1) {
           names.unshift(el.tagName);
        }
        el = el.parentNode;
    }
    return names.join(' -> ');
}

Então registre as mensagens assim:

ngOnInit() {
   this.renderer.listen(this.elementRef.nativeElement, this.logOn, () => {
      const prefix = this.getPrefix();
      console.log(prefix + ' the message here');
   }
}

Artigos relacionados