我试图使用以下代码实现动态组件-
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('Angular2');
但问题是,当我多次使用for循环调用createWidget时,生成的模板是反向有序的。请看我的柱塞https://plnkr.co/edit/hqKYsGlyuk78tg61zjfd?p=preview
在这个柱塞示例中,Angular2比Angular1之前显示。
发布于 2016-12-20 12:34:09
你有两个选择:
1-创建模块是同步的,为了确保组件以与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 );
}
}发布于 2017-05-28 15:51:25
您可以尝试计算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是每个组件的目标索引。
发布于 2016-12-20 12:18:47
只需将0从
this.vcRef.createComponent(factory, 0, injector, []);这使得每个组件被插入到位置0(在所有其他组件之前)。
如果没有显式索引,则在前面添加的组件后面追加每个组件:
this.vcRef.createComponent(factory, {injector: injector, projectableNodes: []});https://stackoverflow.com/questions/41242124
复制相似问题