我使用谷歌地图javascript,我必须在InfoWindow中显示一个角组件。
在我的项目中,我使用Jsonp服务加载google。而不是我有google.maps.Map对象可用。稍后,在组件中,我创建一些标记,并向它们附加一个单击监听器:
TypeScript:
let marker = new google.maps.Marker(opts);
marker.setValues({placeId: item[0]});
marker.addListener('click', (ev: google.maps.MouseEvent) => this.onMarkerClick(marker, ev));然后,在click处理程序中,我要打开一个信息窗口,该窗口包含一个角分量:
TypeScript:
private onMarkerClick(marker: google.maps.Marker, ev: google.maps.MouseEvent) {
var div = document.createElement();
this.placeInfoWindow.setContent(div);
// Magic should happen here somehow
// this.placeInfoWindow.setContent('<app-info-view-element></app-info-view-element>');
this.placeInfoWindow.open(this.map, marker);
}我最后做的是一些香草的JS:
TypeScript:
private onMarkerClick(marker: google.maps.Marker, ev: google.maps.MouseEvent) {
let div = document.createElement('div');
div.className = 'map-info-window-container';
div.style.height = '140px';
div.style.width = '240px';
this.placeInfoWindow.setContent(div);
this.placeInfoWindow.open(this.map, marker);
this.placesService.getPlace(marker.get('id')).subscribe(res => {
this.decorateInfoWindow(div, res.name, marker);
}, error => {
this.decorateInfoWindow(div, ':( Failed to load details: ', marker);
});
}
private decorateInfoWindow(containerEl: HTMLElement, title?:string, marker?:google.maps.Marker) {
let h3 = document.createElement('h3');
h3.innerText = title;
containerEl.appendChild(h3);
let buttonBar = document.createElement('div');
let editButton = document.createElement('button')
editButton.innerText = "Edit";
editButton.addEventListener('click', ev => {
this.editPlace(marker);
});
buttonBar.appendChild(editButton);
containerEl.appendChild(buttonBar);
}正如我所了解到的,问题是创建动态组件的唯一可行方法是使用Angulars ViewContainerRef。
但是没有文档或示例描述如何从动态创建的元素创建ViewContainerRef。
强制框架以某种方式处理DOM是可行的吗?正如在许多线程中所述:“角不处理innerHTML或appendChild”。这完全是死胡同吗?
第二:是否可以使用Renderer实现?(不熟悉它),我看到了这个帆布渲染实验,理论上,我想它也适用于谷歌地图,因为我们可以推断地图只是一种特殊的画布。它是在上一个版本中仍然可用,还是已经改变了?DomRenderer不在文档中,但是我们可以在源代码中找到它。
发布于 2016-12-02 06:27:11
这里的主要规则是来动态创建组件,您需要获得它的工厂.。
1)在entryComponents数组中添加动态组件,并将其包含到declarations中
@NgModule({
...
declarations: [
AppInfoWindowComponent,
...
],
entryComponents: [
AppInfoWindowComponent,
...
],
})这是一个提示角编译器为组件生成ngfactory,即使我们没有在模板中直接使用我们的组件。
2)现在,我们需要将ComponentFactoryResolver注入到我们想要获得的组件/服务中。您可以将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));
});https://stackoverflow.com/questions/40922224
复制相似问题