Angular,如何从字符串解析模板并传递当前上下文变量

2024-02-07

我制作了一个简单的组件来创建表:

@Component({
  selector: 'admin-table',
  template: `
    <table class='table table-bordered'>
      <thead>
      <th *ngFor='let column of columns'>
        {{ column.label }}
      </th>
      </thead>
      <tbody>
      <tr *ngFor="let record of records">
        <td *ngFor='let column of columns' [innerHTML]="fieldContent(column, record) | safeHtml">
        </td>
      </tr>
      </tbody>
    </table>
  `,
})
export class AdminTableComponent {

  @Input() columns: AdminTableColumn[];

  @Input() records: {}[];

  fieldContent(column: AdminTableColumn, record: {}) {
    if (column.template) {
      //TODO: parse the template and pass current record as argument
      return column.template;
    }

    return record[column.field];
  }
}

和其他组件使用上述组件创建产品表

@Component({
  selector: 'product-admin',
  template: `
    <h1>Products</h1>
    <admin-table [columns]="columns" [records]="products"></admin-table>
  `,
  providers: [ProductService],
})
export class ProductAdminComponent implements OnInit {

  products: Product[];

  columns: AdminTableColumn[] = [
    {
      field: 'id',
      label: 'SKU',
    },
    {
      field: 'name',
      label: 'Name',
      template: '<strong>{{record.name}}</strong>',
    }
  ];
}

就像你可以看到的AdminTableColumn有一个附加选项称为template使用模板设置单元格的值。但是当尝试渲染我得到的值时我无法做到这一点{{record.name}}而不是真实的产品名称。

我需要解析输入的值template允许使用角度声明的选项,例如:{{record.name}} or <some-component [title]="record.name"></some-component> 以创建丰富的表。

换句话说,存在类似的东西render(template, { record: record })


您可以为此目的构建特殊指令:

@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;
  }
}

管理组件

@Component({
  selector: 'admin-table',
  template: `
    <table class='table table-bordered'>
      <thead>
      <th *ngFor='let column of columns'>
        {{ column.label }}
      </th>
      </thead>
      <tbody>
      <tr *ngFor="let record of records">
        <td *ngFor='let column of columns'>
          <ng-container *ngIf="column.template as tmpl; else staticTmpl">
            <ng-container *compile="tmpl; context: { record: record }"></ng-container>
          </ng-container>
          <ng-template #staticTmpl>{{record[column.field]}}</ng-template>
        </td>
      </tr>
      </tbody>
    </table>
  `,
})
export class AdminTableComponent {
  @Input() columns: any[];

  @Input() records: {}[];
}

笨蛋的例子 https://plnkr.co/edit/KmbgyNetT7ZJn6UnabVz?p=preview

See also

  • Angular 2.1.0 动态地动态创建子组件 https://stackoverflow.com/questions/40060498/angular-2-1-0-create-child-component-on-the-fly-dynamically
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular,如何从字符串解析模板并传递当前上下文变量 的相关文章

随机推荐