显示标题 string/templateRef Angular

Showing Title string/templateRef Angular

我正在尝试改进我的代码而不是有条件,所以我决定创建一个指令或者可能的话创建一​​个管道,它可以帮助我根据类型(字符串或模板引用)打印选项卡的标题,我的代码如下,这段代码在我的 Tabs/Tab 组件中使用,但也在我的 Stepper/step 组件中使用,所以我相信创建可重用的东西会很棒。我已经尝试使用 ElementRef、Renderer2、ViewContainerRef、TemplateRef 来实现...但我没有成功。

<ng-container *ngIf="tab.isLabelTemplate">
     <ng-container *ngTemplateOutlet="tab.title">
     </ng-container>
</ng-container>
<ng-container *ngIf="!tab.isLabelTemplate">{{ tab.title }}</ng-container>

isLabelTemplate 如下所示:

get isLabelTemplate(): boolean {
  return this.title instanceof TemplateRef;
}

非常感谢:)

您可以利用 Angular low-level API 来动态操作 DOM 的结构:

下面是该指令的示例:

title-template.directive.ts

import { Directive, TemplateRef, Renderer2, ViewContainerRef, Input } from '@angular/core';

@Directive({
  selector: '[titleTemplate]',
})
export class TitleTemplateDirective {
  @Input()
  set titleTemplate(value: string | TemplateRef<any>) {
    this.updateView(value);
  }

  textNode: Text;

  constructor(private vcRef: ViewContainerRef, private renderer: Renderer2) {}

  private updateView(value: string | TemplateRef<any>) {
    this.clear();

    if (!value) {
      return;
    }

    if (value instanceof TemplateRef) {
      this.vcRef.createEmbeddedView(value);
    } else {
      this.textNode = this.renderer.createText(value);
      const elem = this.vcRef.element.nativeElement;

      this.renderer.insertBefore(elem.parentNode, this.textNode, elem);
    }
  }

  private clear() {
    this.vcRef.clear();
    if (this.textNode) {
      this.renderer.removeChild(this.textNode.parentNode, this.textNode);
    }
  }

  ngOnDestroy() {
    this.clear();
  }
}

用法:

<ng-container [titleTemplate]="title"></ng-container>  

Forked Stackblitz

或者您可以将此逻辑移动到 "helper" 组件并在您的 TabComponent 中使用它。所以这个逻辑在一个地方(DRY)。 辅助组件 (TitleComponent) 与您在 TabComponent 中使用的相同。 这样您只需移动 "problem" 但不必一次又一次地重复它。而且它仍然很容易阅读。

...
import { Component, Input, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-title',
  template: `
    <ng-container *ngIf="isLabelTemplate">
      <ng-container *ngTemplateOutlet="title">
      </ng-container>
    </ng-container>
    <ng-container *ngIf="!isLabelTemplate">{{ title }}</ng-container>
  `,
})
export class TitleComponent  {
  @Input() title: string | TemplateRef<any>;

  get isLabelTemplate(): boolean {
    return this.title instanceof TemplateRef;
  }
}


@Component({
  selector: 'app-tab',
  template: `
    <app-title [title]="title"></app-title>
  `,
})
export class TabComponent  {
  @Input() title: string | TemplateRef<any>;
}

...