我创建一个简单的组件来创建表:
@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}}
或<some-component [title]="record.name"></some-component
&gt;为了创建一个丰富的表。
render(template, { record: record })
的东西
答案 0 :(得分:3)
您可以为此目的建立特殊指令:
@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;
}
}
AdminComponent
@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: {}[];
}
<强> Plunker Example 强>
另见
答案 1 :(得分:-1)
我非常确定Angular会清理通过innerHtml注入的html,因此你的字符串插值在那里不起作用。
相反,您可以尝试在fieldContent函数中解析模板并直接添加记录的键。
这是一个使用正则表达式替换{{record [key]}}的所有实例的示例,无论密钥是什么,并返回插入到Html中的插值字符串。
@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) {
let template = column.template;
// Go through the keys and replace all isntances in the field.
// Note that this is strict and will not replace {{ record.name }}
// You may want to add additional regexp to do that.
Object.keys(record).forEach(key => {
template = template.replace(new RegExp(`{{record.${key}}}`, 'g'), 'some name');
});
return template;
}
return record[column.field];
}
}