Angular style viewContainerRef từ mảng Đầu vào Chỉ thị

Nov 12 2020

Tôi đã tạo một chỉ thị sử dụng một mảng có độ dài thay đổi để điền chú giải công cụ. Điều này hoạt động tốt nhưng tôi cần phải tạo kiểu động cho chú giải công cụ để nó vẫn nằm dưới thành phần kích hoạt ban đầu. Sử dụng giá trị trên cùng hoặc dưới cùng thay đổi dựa trên số lượng mục.

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

Tôi đã thử sử dụng ngStyle nhưng không chắc làm thế nào để truy cập vào giá trị divStyle vì nó được tạo bằng viewContainerRef.createEmbeddedView.

Tôi nghĩ một lựa chọn tốt hơn sẽ là thêm các kiểu từ tệp ts bằng cách sử dụng style.bottom nhưng tôi không biết cách thêm kiểu đó. Tôi cần tính toán tooltipDataArray.length, sau đó thêm 10px hoặc lâu hơn vào một biến định vị lại viewContainerRef. Tôi không chắc về cách tốt nhất để tiếp tục.

 @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 ở đây

Trả lời

1 Marshal Nov 12 2020 at 17:41

Nếu bạn sẵn sàng chuyển vào templateReflàm đầu vào cho chỉ thị thì việc này sẽ dễ dàng hơn rất nhiều ...

Với cách triển khai hiện tại của bạn, bạn đang thay thế nội dung của divbằng nội dung được hiển thị của mẫu ...

  • Về cơ bản, đây không phải là một chú giải công cụ và bạn sẽ cần phải tách chúng ra bằng cách nào đó để "mô phỏng chú giải công cụ"

Dưới đây là một cách bạn có thể thực hiện điều này.

Tách ng-templatediv khỏi div để tách chúng và chuyển của bạn #tooltipTemplatedưới dạng giá trị cho [templateRef]đầu vào trêndirective

<div tooltipDirective [templateRef]="tooltipTemplate" [tooltipDataArray]="['Person1', 'Person2']">See tooltip!
</div>
<ng-template #tooltipTemplate>      
    <div class="tooltip">   
        This is my tooltip!
    </div>      
</ng-template>  

Trong chỉ thị của bạn, chuyển đổi của bạn @ContentChildthành một đầu vào để nhận templateRef, tạo của bạn embeddedViewvà thêm các arrayphần tử của bạn .

  • Điều này cũng đơn giản hóa logic của bạn ở đây
  @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);
    });
  }

Điều chỉnh kiểu chung của bạn

.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


Đây sẽ là cách triển khai rõ ràng nhất với giàn giáo mà bạn đã cung cấp ... với điều đó nói rằng, nếu tôi triển khai chỉ thị chú giải công cụ, tôi sẽ nghiên cứu CDK Overlayđể tạo ra một triển khai chú giải công cụ tùy chỉnh.