我可以从字符串创建TemplateRef吗?

时间:2019-03-03 09:20:49

标签: angular

我得到的组件

假设我具有以下超级简单的组件:

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)

是否可以在运行时动态创建基本的简单模板?

1 个答案:

答案 0 :(得分:-1)

在这些示例中,我们实际上并没有“创建”模板引用,因为这需要有角度的渲染器工厂和大量额外的代码来为新的 EmbeddedView 创建合适的注入器。我们只需要使用字符串值即时编辑模板,就可以了。

示例 1:使用 ng-container

使用 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 模板字符串。

示例 2:使用 elementRef

既然我们在第一个例子中注入了 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;  
    }
}

示例 3:使用简单的数据绑定

最后,既然它只是一个简单的字符串模板,我们想在组件中注入为什么不简单地在 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

的文章

希望这对那里的人有用

相关问题