这里的主要规则是动态创建组件,您需要获取其工厂。
1)entryComponents除了包含以下内容外,还将动态组件添加到数组中declarations:
@NgModule({
...
declarations: [
AppInfoWindowComponent,
...
],
entryComponents: [
AppInfoWindowComponent,
...
],
})
即使我们不直接在某些模板中使用我们的组件,这也暗示了角度编译器会为该组件产生ngfactory。
2)现在,我们需要ComponentFactoryResolver在想要获得ngfactory的组件/服务中进行注入。您可以考虑将ComponentFactoryResolver其存储为组件工厂
app.component.ts
import { ComponentFactoryResolver } from '@angular/core'
...
constructor(private resolver: ComponentFactoryResolver) {}
3)现在该去AppInfoWindowComponent工厂了:
const compFactory = this.resolver.resolveComponentFactory(AppInfoWindowComponent);
this.compRef = compFactory.create(this.injector);
4)有了工厂,我们可以随意使用它。这是一些情况:
ViewContainerRef.createComponent(componentFactory,...) 在viewContainer旁边插入组件。
ComponentFactory.create(injector, projectableNodes?, rootSelectorOrNode?) 只需创建组件,即可将此组件插入匹配的元素 rootSelectorOrNode
注意,我们可以在ComponentFactory.create函数的第三个参数中提供节点或选择器。在许多情况下可能会有所帮助。在此示例中,我将简单地创建组件,然后将其插入某个元素。
onMarkerClick 方法可能类似于:
onMarkerClick(marker, e) {
if(this.compRef) this.compRef.destroy();
// creation component, AppInfoWindowComponent should be declared in entryComponents
const compFactory = this.resolver.resolveComponentFactory(AppInfoWindowComponent);
this.compRef = compFactory.create(this.injector);
// example of parent-child communication
this.compRef.instance.param = "test";
const subscription = this.compRef.instance.onCounterIncremented.subscribe(x => { this.counter = x; });
let div = document.createElement('div');
div.appendChild(this.compRef.location.nativeElement);
this.placeInfoWindow.setContent(div);
this.placeInfoWindow.open(this.map, marker);
// 5) it's necessary for change detection within AppInfoWindowComponent
// tips: consider ngDoCheck for better performance
this.appRef.attachView(this.compRef.hostView);
this.compRef.onDestroy(() => {
this.appRef.detachView(this.compRef.hostView);
subscription.unsubscribe();
});
}
5)不幸的是,动态创建的组件不是更改检测树的一部分,因此我们还需要注意更改检测。这可以通过使用ApplicationRef.attachView(compRef.hostView)上面示例中编写的来完成,或者我们可以在要创建动态组件的组件ngDoCheck(示例)中明确地做到这一点(AppComponent以我为例)
app.component.ts
ngDoCheck() {
if(this.compRef) {
this.compRef.changeDetectorRef.detectChanges()
}
}
这种方法更好,因为它仅在更新当前组件时才更新动态组件。另一方面,ApplicationRef.attachView(compRef.hostView)将更改检测器添加到更改检测器树的根,因此将在每个更改检测刻度上调用它。
柱塞示例
提示:
由于addListener是在angular2区域外运行,因此我们需要在angular2区域内显式运行代码:
marker.addListener('click', (e) => {
this.zone.run(() => this.onMarkerClick(marker, e));
});