首页 文章

任意位置Angular 4 / Force ViewChild检测中的组件渲染

提问于
浏览
1

我的Angular 4应用程序使用第三方库(mapbox)来呈现页面上的内容 . 该库具有弹出对话框功能,允许在用户单击 Map 上的图钉时显示弹出窗口:https://www.mapbox.com/mapbox-gl-js/example/popup-on-click/

使用类似以下代码调用弹出窗口:

map.on('click', 'places', function (e) {
    new mapboxgl.Popup()
        .setLngLat(e.features[0].geometry.coordinates)
        .setHTML('<div>this is a popup</div>')
        .addTo(map);
});

我想在弹出div中渲染一个Angular 4组件 . 我试过的事情:

1) Binding a @ViewChild to that popup's div.

// in the component that holds the map component 
@ViewChild("pop", { read: ViewContainerRef }) childContainer: ViewContainerRef;

//when the user clicks the popup
popup.setHTML("<div #pop></div>")

永远不会分配 childContainer . 我已经尝试在弹出窗口打开后等待几秒钟,或者在我的组件的 ChangeDetectorRef 上调用 detectChanges() . 我尝试在 NgZone.runOutsideAngular() 中打开弹出窗口,然后手动运行 detectChanges() .

如果我手动将div添加到我的html模板,弹出窗口会按预期呈现给div的位置 .

2) Rendering it using a factory to a div with that ID

//when the user clicks the popup
popup.setHTML("<div id="pop">HERE</div>")

const element = this.elRef.nativeElement.querySelector("#pop"); //this is found
const factory = this.componentFactoryResolver.resolveComponentFactory(PopupComponent);
const component = factory.create(this.viewContainerRef.injector, null, element);

div HERE的内容被替换为 <!----> . 显然Angular正在向该位置呈现某些内容,而不是实际的组件 . 我需要不同的注射器吗?

3) Placing the component render element directly into the popup:

popup.setHTML("<popup-component></popup-component>")

它永远不会变成一个实际的组件 . 即使像 detectChanges()NgZone 这样的东西也会运行 .

4) Any other ideas? How do I render an Angular component to an arbitrary html location defined outside of Angular?

1 回答

  • 1

    我能够使用标准 .append 来解决这个问题 . 我不会在这里张贴它,以防其他人发现这个问题 .

    将隐藏的组件添加到与 Map 相同的页面:

    //map.component.html
    <div id="map"></div>
    <div style="display:none">
        <info-popup #infopop [id]="selectedId" [renderTo]="popupLocation"></info-popup>       
    </div>
    

    将点击的弹出按ID绑定到传递给上面的info-pop组件的类属性

    //map.component.ts   
    popupLocation: any;
    selectedId: any;
    initializeMap(): void {
      this.map.on("click", "pinLayer", (e: MapMouseFeaturesEvent) => {
         this.selectedId = e.features[0].properties["id"]; // assumes a distinct id per pin
         new mapboxgl.Popup({ closeButton: false })
                .setLngLat(e.lngLat)
                .setHTML("<div id='popupLocation'></div>")
                .addTo(this.map);
         this.popupLocation = this.elementRef.nativeElement.querySelector("#popupLocation);
      });
    }
    

    使用附加的组件:

    //infopop.component.ts
    export class InfoPopupComponent implements OnChanges {
    
        @Input() id: string;
        @Input() renderTo: any;
     constructor(private elementRef: ElementRef) { }
    
    
        ngOnChanges(changes: SimpleChanges): void {
            if ("id" in changes) {
                // load popup specific details and render
            }
            if (this.renderTo) {
                this.renderTo.append(this.elementRef.nativeElement);
            }
        }
    }
    

    这适用于infopop.component.html正确传递的绑定[click]事件 .

相关问题