显示标题 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 的结构:
ViewContainerRef::createEmbeddedView 在指令的宿主元素附近呈现 TemplateRef
Renderer2::insertBefore 在指令的宿主元素附近呈现 TextNode
下面是该指令的示例:
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>
或者您可以将此逻辑移动到 "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>;
}
...
我正在尝试改进我的代码而不是有条件,所以我决定创建一个指令或者可能的话创建一个管道,它可以帮助我根据类型(字符串或模板引用)打印选项卡的标题,我的代码如下,这段代码在我的 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 的结构:
ViewContainerRef::createEmbeddedView 在指令的宿主元素附近呈现 TemplateRef
Renderer2::insertBefore 在指令的宿主元素附近呈现 TextNode
下面是该指令的示例:
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>
或者您可以将此逻辑移动到 "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>;
}
...