动态加载现有组件
Load existing components dynamically Angular 2 Final Release
我正在尝试动态加载最终版本2.0.0中的组件。
使用RC5,我正在使用以下代码加载:
创建一个指令来加载控件:
import {
CheckboxComponent, CheckboxListComponent,DatePickerComponent
} from '../components/';
@Directive({
selector: '[ctrl-factory]'
})
export class ControlFactoryDirective implements OnChanges {
@Input() model: any;
constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
}
create(cp) {
this.resolver.resolveComponent(cp)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.vcRef.createComponent(factory, 0, injector, []);
let ch = this.vcRef.createComponent(factory, 0, injector, []).instance;
ch.model = this.model;
});
}
ngOnChanges() {
if (!this.model) return;
switch (this.model.type) {
case 'checkbox':
this.create(CheckboxComponent);
break;
case 'checkboxlist':
this.create(CheckboxListComponent);
break;
case 'datepicker':
this.create(DatePickerComponent);
break;
default:
break;
}
}
}
然后将该指令加载到我的页面中,像这样:
<div ctrl-factory *ngFor="let child of page.childrens" [model]="child"></div>
但是从rc5升级到2.0.0最终版本后,解析器不再存在了,被编译器取代了。
我发现很多地方展示了如何使用不同的代码加载它,但是所有这些都太复杂了,我无法使它工作。
举个例子:在Angular 2.0中,我如何使用/create动态模板来编译动态组件?
它看起来更具体的场景,我的一个,我只需要加载组件并设置一个@Input名为model。
当我尝试一件事时,我必须为每个组件动态创建一个模块,然后将组件添加到其中。但是后来我有问题说组件被设置在多个模块中,试图在某些地方删除而不工作。
显示的代码的主要部分,我从这个链接:http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2-rc-5/
做了一些改变。
更新
我设法使它工作,使用以下方法:
create方法已更改为
private create(cp) {
@NgModule({
imports: [BrowserModule, ControlsModule],
declarations: []
})
class DynamicModule {}
this.compiler.compileModuleAndAllComponentsAsync(DynamicModule)
.then(({componentFactories}) => {
const compFactory = componentFactories.find(x => x.componentType === cp);
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
const cmpRef = this.vcRef.createComponent(compFactory, 0, injector, []);
cmpRef.instance.model = this.model;
});
}
在我发现的大多数地方,设置创建组件并将其设置为DynamicModule,这样做的问题是,当你已经在不同的模块中声明相同的组件时,angular会抱怨。在我的情况下,解决方案是导入我的ControlsModule,它导出了我所有的控件。
更新
NgComponentOutlet是在4.0.0-beta中引入的。3 https://github.com/angular/angular/commit/8578682
即将推出NgComponentOutlet
我看到了两个选项:
1)使用ComponentFactoryResolver。它使用已经生成的工厂,代码看起来像这样:
constructor(private vcRef: ViewContainerRef, private resolver: ComponentFactoryResolver) { }
create(comp) {
const factory = this.resolver.resolveComponentFactory(comp);
const compRef = this.vcRef.createComponent(factory);
(<any>compRef).instance.model = this.model;
}
在这种情况下,我们必须在模块
的装饰器中定义declarations
和entryComponents
属性中的动态组件@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent, DynamicComponent ],
entryComponents: [DynamicComponent],
bootstrap: [ AppComponent ]
})
export class AppModule { }
- 使用Angular 2.0动态创建组件<
- 恰好例子/gh>
在这种情况下,我们只能通过使用compiler.compileModuleAndAllComponentsAsync
运行模块编译,然后从componentFactories数组中找到组件。你的指令可能像这样:
constructor(private vcRef: ViewContainerRef, private loader: DynamicLoaderService) { }
create(comp) {
this.loader.createComponentFactory(comp).then(factory => {
const compRef = this.vcRef.createComponent(factory);
(<any>compRef).instance.model = this.model;
})
}
DynamicLoaderService
是一个全局服务,它将加载和存储组件工厂。
@Injectable()
export class DynamicLoaderService {
constructor(protected compiler: Compiler) {}
private resolveCompHelper$ = new Subject<any>();
private cache = new Map<string, ComponentFactory<any> | number>();
public createComponentFactory(type: string) : Promise<ComponentFactory<any>> {
let factory = this.cache.get(type);
// if factory has been already loading
if(factory === 1) {
return new Promise((resolve) => {
// waiting compilation of factory
const subscriber = this.resolveCompHelper$.subscribe((data) => {
if(type !== data.type) return;
subscriber.unsubscribe();
resolve(data.factory);
});
});
}
// factory exists in cache
if (factory) {
return new Promise((resolve) => resolve(factory));
}
const comp = typeMap[type];
// factory startes loading
this.cache.set(type, 1);
return new Promise((resolve) => {
this.compiler.compileModuleAndAllComponentsAsync(createComponentModule(comp))
.then((moduleWithFactories: ModuleWithComponentFactories<any>) => {
factory = moduleWithFactories.componentFactories
.find(x => x.componentType === comp);
this.cache.set(type, factory);
this.resolveCompHelper$.next({ type, factory});
resolve(factory);
});
});
}
}
<恰好例子/strong>
希望它能帮助你!
这是有用的,我看到这个选项基于一个指令,但我找到了一个适合我的需求基于组件:https://www.ag-grid.com/ag-grid-angular-aot-dynamic-components/
编码快乐!
- 如何创建带有插槽的vue js组件预加载程序
- 加载器组件仅加载一次
- 如何在ReactJs中渲染子组件时重新加载子组件的数据
- 加载服务器端渲染的React组件后执行脚本
- 在reactjs组件中预加载数据
- 在foreach中加载所有项后,Knockoutjs组件回调
- ReactJS-在加载时渲染顶级组件
- 可以't在我的React组件中加载图像
- 使用javascript加载knockoutjs组件
- 将自定义脚本加载到Vue.js组件中
- 如何在加载Angular2.RC1子组件时更新它
- Angular2 - 动态组件加载器错误
- 使用*ngIf+模板变量+loadIntoLocation以编程方式将组件加载到视图中
- 反应组件加载问题
- 反应组件加载模式(或反模式?
- Ember组件加载存储数据
- noflo:动态组件加载-组件[name]与基础[path]不可用
- 在angular组件加载时附加jQuery事件
- KnockoutJS 自定义组件加载器未执行“loadViewModel”
- 在 Angular2 中使用动态组件加载器的双向数据绑定