我正在尝试使用以下代码实现动态组件 -
createWidget(template: string) {
const html = template;
if (!html) return;
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: html
});
this.createComponentFactory( this.compiler, compMetadata )
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
console.log("Injector: " + injector);
this.vcRef.createComponent(factory, 0, injector, []);
console.log( "Create Widget End.." );
});
}
createComponentFactory( compiler: Compiler, metadata: Component) {
@Component( metadata )
class DynamicComponent { };
@NgModule({
imports: [ CommonModule, FormsModule ],
declarations: [ DynamicComponent ]
})
class DynamicHtmlModule { }
return compiler.compileModuleAndAllComponentsAsync( DynamicHtmlModule )
.then(( moduleWithComponentFactory: ModuleWithComponentFactories<any> ) => {
return moduleWithComponentFactory.componentFactories.find( x => x.componentType === DynamicComponent );
});
}
当我使用 - 调用createWidget方法时,代码运行正常
this.createWidget(&#39; Angular2&#39);
但问题是当我使用for循环多次调用 createWidget 时,生成的模板是反向排序的。请参阅我的plunker https://plnkr.co/edit/hqKYsGlyuk78tg61zjfd?p=preview
在这个plunker示例中,Angular2之前显示的是Angular1。
答案 0 :(得分:2)
您有两种选择:
1 - 创建模块Asyncrounously,你已经在做了,为了确保你的组件以与for循环相同的顺序出现在DOM中,你需要使用你的像这样的循环索引:
for(var i = 1; i <= 2; i++) {
this.createWidget('<h1>Angular' + i + '</h1>' , i-1); // minus 1 because you're starting from 1 !!!!!
}
createWidget(template: string , index) {
const html = template;
if (!html) return;
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: html
});
this.createComponentFactory( this.compiler, compMetadata )
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.vcRef.createComponent(factory, index, injector, []);
});
}
因为在循环内部有一个异步函数(createComponentFactory),所以你永远不能保证第一个组件总是先创建而第二个组件是第二个,因为第一个组件的编译可能需要超过秒,然后第二个组件将被解析首先。
对于这种情况,传递索引更加具体和可信,并确保将它们放在for循环的相同顺序中。
这是你的傻瓜,工作正常。
https://plnkr.co/edit/VmmwzzrcJq6En5tXcyl6?p=preview
2 - 要同步创建模块,然后您可以相信它们将始终按顺序显示而不自行定义索引。
export class App {
name:string;
constructor(public compiler: Compiler, public vcRef: ViewContainerRef) {
this.name = 'Angular2';
for(var i = 1; i <= 2; i++) {
this.createWidget('<h1>Angular' + i + '</h1>');
}
}
createWidget(template: string ) {
const html = template;
if (!html) return;
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: html
});
let factory = this.createComponentFactory( this.compiler, compMetadata )
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.vcRef.createComponent(factory, undefined , injector, []);
}
createComponentFactory( compiler: Compiler, metadata: Component ) {
@Component( metadata )
class DynamicComponent { };
@NgModule({
imports: [ CommonModule ],
declarations: [ DynamicComponent ]
})
class DynamicHtmlModule { }
let moduleWithComponentFactory = compiler.compileModuleAndAllComponentsSync( DynamicHtmlModule )
console.log(moduleWithComponentFactory.componentFactories)
return moduleWithComponentFactory.componentFactories.find( x => x.componentType === DynamicComponent );
}
}
答案 1 :(得分:1)
您可以尝试为index
方法计算vcRef.createComponent
,例如
loadedIndices: number[] = [];
...
let renderedIndex = this.loadedIndices.indexOf(Math.max.apply(Math, this.loadedIndices.filter(x => x <= index))) + 1;
this.vcRef.createComponent(factory, renderedIndex, injector, []);
this.loadedIndices.push(index);
this.loadedIndices.sort((a, b) => a - b);
其中index
是每个组件的目标索引
<强> Plunker Example 强>
答案 2 :(得分:0)
只需从
中删除0
即可
this.vcRef.createComponent(factory, 0, injector, []);
这使得每个组件都插入位置0(在所有其他组件之前)。
如果没有显式索引,则在添加之前添加每个组件:
this.vcRef.createComponent(factory, {injector: injector, projectableNodes: []});