Angular2 - 如何动态创建组件并附加到body的viewcontainer

时间:2016-12-16 23:28:42

标签: angular

我一直在尝试动态创建组件并将其附加到文档标记。我一直很难弄清楚如何选择正文的ViewContainterRef,所以我可以使用ComponentFactoryResolver添加一个新的组件。

我尝试使用下面的代码获取对body容器的引用,但它不起作用。有谁知道怎么做?谢谢!

import {
    Component,
    ComponentRef,
    ApplicationRef,
    Injector,
    Input,
    ViewContainerRef,
    ComponentFactoryResolver,
    ViewChild,
    OnInit,
    OnDestroy
} from '@angular/core';

import {
    ModalComponent
} from './modal.component';

@Component({
    selector: 'my-modal'
})
export class MyModalComponent {

    private _bodyRef: ViewContainerRef;


    constructor(private resolver: ComponentFactoryResolver, private app: ApplicationRef) {

        // Does not work!
        this._bodyRef = app['_rootComponents'][0]['_hostElement'].vcRef;

    }


    ngOnInit() {

        // Calls the factory to crate a brand new instance
        let componentFactory = this.resolver.resolveComponentFactory(ModalComponent);
        this._bodyRef.createComponent(componentFactory);


    }
}

2 个答案:

答案 0 :(得分:6)

Angular2材料团队正在为工具提示和其他动态组件执行类似的操作,视图可能位于当前容器引用之外。

这是班级:https://github.com/angular/material2/blob/master/src/lib/core/portal/dom-portal-host.ts 他们在做什么:

首先注入一堆有用的类:

constructor(
      private _viewRef: ViewContainerRef,
      private _hostDomElement: Element,
      private _componentFactoryResolver: ComponentFactoryResolver,
      private _appRef: ApplicationRef,
      private _defaultInjector: Injector) {
  }

然后: 在当前viewContainerRef中创建组件,在您的情况下是您的模态。

ngOnInit() {

        // Calls the factory to crate a brand new instance
        let componentFactory = this._componentFactoryResolver.resolveComponentFactory(ModalComponent);
        let componentRef = this._viewRef.createComponent(componentFactory);


    }

然后将其附加到appRef

 (this._appRef as any).attachView(componentRef.hostView);

        this.setDisposeFn(() => {
          (this._appRef as any).detachView(componentRef.hostView);
          componentRef.destroy();
        });

我从来没有这样做过,所以你可能需要付出一些努力,但我认为这就是方法。

答案 1 :(得分:2)

我通过单独的服务解决了这个问题:

afr[dafr['b'].apply(lambda x: 2 in x)]

然后在你的组件中:

import {
  Injectable,
  ComponentFactoryResolver,
  ApplicationRef,
  Injector,
  EmbeddedViewRef,
  ComponentRef
} from '@angular/core';

@Injectable()
export class DOMService {

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

  appendComponentToBody(component: any) {
    //create a component reference
    const componentRef = this.componentFactoryResolver.resolveComponentFactory(component)
      .create(this.injector);

    // attach component to the appRef so that so that it will be dirty checked.
    this.applicationRef.attachView(componentRef.hostView);

    // get DOM element from component
    const domElem = (componentRef.hostView as EmbeddedViewRef < any > )
      .rootNodes[0] as HTMLElement;

    document.body.appendChild(domElem);

    return componentRef;
  }

  removeComponentFromBody(componentRef: ComponentRef < any > ) {
    this.applicationRef.detachView(componentRef.hostView);
    componentRef.destroy();
  }
}