Vista de estilo angularContainerRef de la matriz de entrada de directiva
He creado una directiva que utiliza una matriz de longitud variable para completar una información sobre herramientas. Esto funciona muy bien, pero necesito diseñar dinámicamente la información sobre herramientas para que permanezca debajo del componente de activación inicial. Usando un valor superior o inferior que cambia según la cantidad de elementos.
<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>
Intenté usar ngStyle pero no estoy seguro de cómo obtener acceso al valor divStyle porque este se crea usando viewContainerRef.createEmbeddedView.
Pensé que una mejor opción sería agregar los estilos del archivo ts usando style.bottom pero no sé cómo agregar eso. Necesito calcular tooltipDataArray.length y luego agregar 10px más o menos a una variable que reposiciona el viewContainerRef. No estoy seguro de cuál es la mejor forma 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 aquí
Respuestas
Si estuviera dispuesto a pasar el templateRefcomo entrada a la directiva, esto sería mucho más fácil ...
Con su implementación actual, está reemplazando el contenido del
divcon el contenido renderizado de la plantilla ...
- Básicamente, esto no es una información sobre herramientas y necesitaría desacoplarlos de alguna manera para "simular una información sobre herramientas".
A continuación se muestra una forma en que puede lograr esto.
Separe el ng-templatediv del div para desacoplarlos, y pase su #tooltipTemplatecomo un valor a la [templateRef]entrada en eldirective
<div tooltipDirective [templateRef]="tooltipTemplate" [tooltipDataArray]="['Person1', 'Person2']">See tooltip!
</div>
<ng-template #tooltipTemplate>
<div class="tooltip">
This is my tooltip!
</div>
</ng-template>
En su directiva, convierta su @ContentChilden una entrada para recibir templateRef, crear embeddedViewy agregar sus arrayelementos.
- Esto también simplifica su lógica aquí
@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);
});
}
Ajusta tu 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 sería la implementación más limpia con el andamio que ha proporcionado ... Dicho esto, si tuviera que implementar una directiva de información sobre herramientas, investigaría CDK Overlaypara crear una implementación personalizada de información sobre herramientas.