如何从结构指令渲染字符串?

时间:2020-11-12 18:25:31

标签: angular

ViewContainerRef提供方法createEmbeddedView(接受TemplateRef用于渲染模板)和createComponent(接受ComponentFactory用于呈现组件)。但是简单的字符串呢?

我看到的唯一解决方法是先拥有DummyComponent,然后将document.createTextNode('string')馈送到projectableNodes

@Component({ template: `<ng-content></ng-content>` }) class DummyComponent {}
const dummyComponentFactory = this.cfr.resoveComponentFactory(DummyComponent)
const nodes = [[document.createTextNode('string')]]
this.viewContainerRef.createComponent(dummyComponentFactory, 0, injector, nodes)

但这只是滥用API,并且呈现简单字符串的开销很大。

2 个答案:

答案 0 :(得分:2)

如果您真的想通过指令来实现它,那是可能的。请参考下面的指令代码:-

import {
  Directive,
  Input,
  NgIterable,
  OnChanges,
  OnInit,
  Renderer2,
  TemplateRef,
  ViewContainerRef
} from "@angular/core";

@Directive({
  selector: "[ngJoin]"
})
export class NgJoinDirective<T, U extends NgIterable<T> = NgIterable<T>>
  implements OnInit, OnChanges {
  @Input() ngJoinOf: any[];
  @Input() ngJoinSeparator: string = ",";
  constructor(
    private _viewContainer: ViewContainerRef,
    private _template: TemplateRef<any>,
    private renderer2: Renderer2
  ) {}

  ngOnChanges() {
    this.createText();
  }

  ngOnInit() {
    this.createText();
  }

  createText() {
    if (this.ngJoinOf) {
      this._viewContainer.clear();
      console.log(this.ngJoinOf);
      const container = this._template.createEmbeddedView({});
      const parentNode = container.rootNodes[0];
      const textNode = this.renderer2.createText(
        this.ngJoinOf.join(this.ngJoinSeparator)
      );
      this.renderer2.insertBefore(parentNode, textNode, parentNode.firstChild);
      this._viewContainer.insert(container);
    }
  }
}

并在html中使用,如下所示:-

<p *ngJoin="let item of arr;separator: '/'">

如果您不提供分隔符,它将使用,作为默认分隔符。

正在工作的Stackblitz:-

https://stackblitz.com/edit/angular-rumkzc?file=src/app/app.component.html

如果您只是想通过使用分隔符的模板连接来打印数组,则管道将是理想的选择,而不是指令。这样的管道是由图书馆提供的。

https://github.com/fknop/angular-pipes

管道名称为join。

注意:-我还没有处理过,您可能想处理的任何极端情况。

答案 1 :(得分:0)

为什么不使用管道来转换数据?

在任何情况下,ViewContainerRef只能渲染组件,因此-您可以使用要显示的字符串的Input创建一个组件,并动态创建它。像这样的东西:

@Component({ template: `{{text}}` }) class DummyComponent {
   @Input text: string;
}

但是我认为管道更适合您的情况。