从投影的子组件 Angular 5 内部获取父 ViewContainerRef

use*_*525 4 angular angular5

我有一个带有动态创建组件的 App 组件。父组件有一个<ng-content>元素,以便我们可以将子组件投影到父组件中。

应用组件:

@Component({
  selector: 'my-app',
  template:`<ng-container #parentcontainer></ng-container>`,
})
Run Code Online (Sandbox Code Playgroud)

父组件:

@Component({
  selector: 'parent',
  template: `
  <ng-container #container></ng-container>
  <ng-content></ng-content>

                `
})
Run Code Online (Sandbox Code Playgroud)

子组件:

@Component({
  selector: 'child',
  template: `<label>
                <input type="radio">
              </label>
                `
})
Run Code Online (Sandbox Code Playgroud)

我的问题是,有什么方法可以访问子组件内的 App 组件的 ViewContainerRef (#parentcontainer) 吗?目标是在稍后阶段动态地将其他组件插入 #parentcontainer 中,例如从子组件单击某些按钮。

这是StackBlitz上的工作示例

Dre*_*nai 7

您可以从子组件中创建一个新组件,并将其 HTML 元素附加到 DOM 中您喜欢的任何位置

// remember to add YourComponent to entryComponents: [] of the module
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(YourComponent);
let componentRef = viewContainerRef.createComponent(componentFactory, index);

componentRef.instance.model = model; // where model is an input
componentRef.changeDetectorRef.detectChanges(); // update it's view
let htmlElement = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;

// Now do what you want with the htmlElement e.g. document.querySelector('body').appendChild(htmlElement)
Run Code Online (Sandbox Code Playgroud)

这对你有用吗?请注意,该组件只会在子组件活着时才保持活着

或者,要在应用程序持续时间内保持组件处于活动状态,请创建一个服务并在 AppComponent 级别提供一次。请注意,这使用ApplicationRef,它允许您调用attachView() - 这可能是一个解决方案

constructor(
      private componentFactoryResolver: ComponentFactoryResolver,
      private appRef: ApplicationRef,
      private injector: Injector
  ) { }

  appendComponentToBody(component: any) {
    const componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);    
    this.appRef.attachView(componentRef.hostView);
    const domElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;    
    // Append to body or wherever you want
    document.body.appendChild(domElem);
  }
Run Code Online (Sandbox Code Playgroud)

这里有关于服务示例的更多详细信息

最好的解决办法可能是使用的角度材质CDK功能的门户网站和PortalHost。这是相当新的,但它的目的是从运行在实际 my-app 元素之外的 Angular 应用程序中创建组件 - 这可能是一个更好的长期解决方案 - 它用于在他们的示例中制作模态等