ViewContainerRef de estilo angular da matriz de entrada da diretiva
Eu criei uma diretiva que usa uma matriz de comprimento variável para preencher uma dica de ferramenta. Isso funciona muito bem, mas preciso estilizar dinamicamente a dica de ferramenta para que permaneça sob o componente acionador inicial. Usando um valor superior ou inferior que muda com base no número de itens.
<div tooltipDirective [tooltipDataArray]="['Person1', 'Person2', 'Person3', 'Person4', 'Person5', 'Person6']">See tooltip!
<ng-template #tooltipTemplate >
<div class="tooltip" [ngStyle]="{'top.px': divStyle}"> // Not sure if this is the correct approach as can't bind to divStyle in the directive
</div>
</ng-template>
</div>
Tentei usar ngStyle, mas não tenho certeza de como obter acesso ao valor divStyle porque ele é criado usando viewContainerRef.createEmbeddedView.
Achei que a melhor opção seria adicionar os estilos do arquivo ts usando style.bottom, mas não sei como adicionar isso. Preciso calcular tooltipDataArray.length e adicionar 10px ou mais a uma variável que reposiciona viewContainerRef. Não tenho certeza da melhor maneira de proceder.
@Input() tooltipDataArray: string[];
@ContentChild("tooltipTemplate") private tooltipTemplateRef: TemplateRef<Object>;
@HostListener("mouseenter") onMouseEnter(): void {
console.log(this.tooltipDataArray);
const view = this.viewContainerRef.createEmbeddedView(
this.tooltipTemplateRef
);
this.tooltipDataArray.forEach(el => {
const child = document.createElement("div");
child.innerText = el;
this.renderer.appendChild(view.rootNodes[1], child);
});
// Somthing like this.viewContainerRef.styles.bottom = 10 x this.tooltipDataArray.length + 'px'
console.log(view.rootNodes)
view.rootNodes.forEach(node => {
this.renderer.appendChild(this.elementRef.nativeElement, node);
});
}
@HostListener("mouseleave") onMouseLeave(): void {
if (this.viewContainerRef) {
this.viewContainerRef.clear();
}
stackBlitz aqui
Respostas
Se você estivesse disposto a passar templateRefcomo uma entrada para a diretiva, isso seria muito mais fácil ...
Com sua implementação atual, você está substituindo o conteúdo de pelo
divconteúdo renderizado do modelo ...
- Isso essencialmente não é uma dica de ferramenta e você precisaria separá-los de alguma forma para "simular uma dica de ferramenta"
Abaixo está uma maneira de fazer isso.
Separe o ng-templatedo div para separá-los e passe o seu #tooltipTemplatecomo um valor para a [templateRef]entrada nodirective
<div tooltipDirective [templateRef]="tooltipTemplate" [tooltipDataArray]="['Person1', 'Person2']">See tooltip!
</div>
<ng-template #tooltipTemplate>
<div class="tooltip">
This is my tooltip!
</div>
</ng-template>
Em sua diretiva, converta seu @ContentChildem uma entrada para receber o templateRef, crie seu embeddedViewe adicione seus arrayelementos.
- Isso também simplifica sua lógica aqui
@Input() templateRef: TemplateRef<Object>;
@HostListener("mouseenter") onMouseEnter(): void {
const view = this.viewContainerRef.createEmbeddedView(this.templateRef);
this.tooltipDataArray.forEach(el => {
const child = document.createElement("div");
child.innerText = el;
this.renderer.appendChild(view.rootNodes[1], child);
});
}
Ajuste seu estilo global
.tooltip {
position: absolute;
/* bottom: -40px; */
left: 15px;
padding: 10px;
background: red;
border-radius: 5px;
/* box-shadow: 0 2px 1px rgba(0, 0, 0, 0.6); */
}
STACKBLITZ
https://stackblitz.com/edit/angular-zr2ydx?file=app/tooltip.directive.ts
Esta seria a implementação mais limpa com o scaffold que você forneceu ... dito isso, se eu fosse implementar uma diretiva de dica de ferramenta, eu pesquisaria CDK Overlaypara criar uma implementação de dica de ferramenta personalizada.