假设我具有以下超级简单的组件:
class MyComponent {
@Input()
simpleContent: string;
@ContentChild(TemplateRef)
content: TemplateRef<any>;
}
<div>
<div *ngIf="simpleContent; else complexContent">{{simpleContent}}</div>
<ng-template #complexContent>
<ng-container [ngTemplateOutlet]="content"></ng-container>
</ng-template>
</div>
用户可以选择使用它,如下所示:
<my-component simpleContent="Hello world!"></my-component>
或者可以这样使用:
<my-component>
<ng-template>Hello world!</ng-template>
</my-component>
尽管第二个选项允许嵌入HTML,从而实现更复杂的格式设置,但用户可以在大多数情况下选择仅带有属性的简单方法。
我想简化组件并摆脱模板中的if / else。我想像这样:
class MyComponent {
@ContentChild(TemplateRef)
content: TemplateRef<any>;
@Input()
set simpleContent(value: string) {
this.content = new TemplateRef(value);
}
}
<div>
<ng-container [ngTemplateOutlet]="content"></ng-container>
</div>
显然这是行不通的,因为不可能使用new TemplateRef(value)
。
是否可以在运行时动态创建基本的简单模板?
答案 0 :(得分:-1)
在这些示例中,我们实际上并没有“创建”模板引用,因为这需要有角度的渲染器工厂和大量额外的代码来为新的 EmbeddedView 创建合适的注入器。我们只需要使用字符串值即时编辑模板,就可以了。
使用 ng-container 扩展 OP 问题的模板降价
<div>
<ng-container #container></ng-container>
</div>
<!-- Adding an empty template for later use -->
<ng-template #content><ng-content></ng-content></ng-template>
然后组件的代码看起来像这样
export class Component implements AfterViewInit{
@ViewChild("content") contentRef: TemplateRef<any>;
@ViewChild("container", {read: ViewContainerRef}) containerRef: ViewContainerRef;
divRef: HTMLElement;
value: string = "";
@Input()
set simpleContent(value: string) {
if(this.divRef){
this.divRef.innerHTML = this.value;
}
this.value = value;
}
constructor() {}
ngAfterViewInit(): void {
let div = document.createElement("div");
div.innerHTML = this.value;
var embeddedViewRef = this.contentRef.createEmbeddedView(this.containerRef);
this.containerRef.insert(embeddedViewRef);
embeddedViewRef.rootNodes[0].replaceWith(div);
this.divRef = div;
}
}
在这个例子中,我们得到了一个位于 EmbeddedView 的 rootNodes 中的 ng-content 标签的引用,并将它替换为我们的原生 html 模板字符串。
既然我们在第一个例子中注入了 nativeElements,我想为什么不直接编辑第一个 div 标签,通过 ViewChild 和 ElementRef 获取它的引用。
@Component({
selector: "component",
template:`<div #ref></div>`
})
export class Component implements AfterViewInit{
@ViewChild("ref", {read: ElementRef}) tref: ElementRef;
value: string = "";
@Input()
set simpleContent(value: string) {
if(this.tref) this.tref.nativeElement.innerHTML = this.value;
this.value = value;
}
constructor() {}
ngAfterViewInit(): void {
this.tref.nativeElement.innerHTML = this.value;
}
}
最后,既然它只是一个简单的字符串模板,我们想在组件中注入为什么不简单地在 innerHTML 上使用 databinding
@Component({
selector: "component",
template:`<div [innerHTML]="value"></div>`
})
export class Component{
value: string = "";
@Input()
set simpleContent(value: string) {
this.value = value;
}
constructor() {}
}
将近 2 年后,我怀疑 OP 仍在等待答案。这个回复对我来说主要是一个挑战,但我自己在研究中学到了一些东西。喜欢这篇关于dom manipulation techniques in angular
的文章希望这对那里的人有用