Angular2, evaluate template from string inside a component

前端 未结 3 751
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-01 13:32

It\'s possible evaluate template from string in a variable?. I need place the string in the component instead of the expression, e.g.

template: \"

相关标签:
3条回答
  • 2020-12-01 13:51

    You can create your own directive that will do it:

    compile.directive.ts

    @Directive({
      selector: '[compile]'
    })
    export class CompileDirective implements OnChanges {
      @Input() compile: string;
      @Input() compileContext: any;
    
      compRef: ComponentRef<any>;
    
      constructor(private vcRef: ViewContainerRef, private compiler: Compiler) {}
    
      ngOnChanges() {
        if(!this.compile) {
          if(this.compRef) {
            this.updateProperties();
            return;
          }
          throw Error('You forgot to provide template');
        }
    
        this.vcRef.clear();
        this.compRef = null;
    
        const component = this.createDynamicComponent(this.compile);
        const module = this.createDynamicModule(component);
        this.compiler.compileModuleAndAllComponentsAsync(module)
          .then((moduleWithFactories: ModuleWithComponentFactories<any>) => {
            let compFactory = moduleWithFactories.componentFactories.find(x => x.componentType === component);
    
            this.compRef = this.vcRef.createComponent(compFactory);
            this.updateProperties();
          })
          .catch(error => {
            console.log(error);
          });
      }
    
      updateProperties() {
        for(var prop in this.compileContext) {
          this.compRef.instance[prop] = this.compileContext[prop];
        }
      }
    
      private createDynamicComponent (template:string) {
        @Component({
          selector: 'custom-dynamic-component',
          template: template,
        })
        class CustomDynamicComponent {}
        return CustomDynamicComponent;
      }
    
      private createDynamicModule (component: Type<any>) {
        @NgModule({
          // You might need other modules, providers, etc...
          // Note that whatever components you want to be able
          // to render dynamically must be known to this module
          imports: [CommonModule],
          declarations: [component]
        })
        class DynamicModule {}
        return DynamicModule;
      }
    }
    

    Usage:

    @Component({
      selector: 'product-item',
      template: `
        <div class="product">
          <ng-container *compile="template; context: this"></ng-container>
        </div>
      `,
    })
    export class ProductItemComponent {
      @Input() name: string;
      @Input() price: number = 0;
      @Input() template: string = `{{ name }} <b>{{ price | currency }}</b>`;
    }
    

    Plunker Example

    See also

    • Angular 2.1.0 create child component on the fly, dynamically
    0 讨论(0)
  • 2020-12-01 13:59

    not sure how you're building the template string

    import { ..., OnInit } from '@angular/core';
    
    @Component({
        selector: 'product-item',
        template: `
        <div class="product" [innerHtml]='template_string'>
        </div>`,
        })
    export class ProductItemComponent implements OnInit {
        @Input() name: string;
        @Input() price: number = 0;
        @Input() pre: string;
        @Input() mid: string;
        @Input() post: string;
        template_string;
        ngOnInit() {
            // this is probably what you want
            this.template_string = `${this.pre}${this.name}${this.mid}${this.price}${this.post}`
        }
    }
    
    <product-item [name]="name" [price]="price" pre="<em>" mid="</em><b>" post="</b>"></product-item>
    

    the string can be built from outside the component, would still recommend something like ngIf to control dynamic templates though.

    0 讨论(0)
  • 2020-12-01 13:59

    In Angular double curly braces {{}} are used to evaluation an expression in a component's template. and not work on random strings or dynamically added DOM elements. So one way of doing this is to use typescript string interpolation using ${}. check the rest of code to understand

    @Component({
      selector: 'product-item',
      template: `
        <div class="product" [innerHTML]="template"></div>`,
    })
    export class ProductItemComponent {
      @Input() name: string;
      @Input() price: number = 0;
      @Input() template: string = `${ this.name } <b>${ this.price }}</b>`;
    }
    
    0 讨论(0)
提交回复
热议问题