Angular 2 动态地将组件插入到特定的 DOM 节点中,而不使用 ViewContainerRef

问题描述 投票:0回答:3

我有一个关于 Angular 2 rc5 中动态组件创建的问题。

所以我们假设我们有两个简单的角度分量:

  @Component({
      template: `
        <div id="container">
          <h1>My Component</h1>
        </div>
       `,
      selector: 'my-app'
  })
  export class AppComponent { }

  @Component({
      template: '<p>{{text}}</p>',
      selector: 'simple-cmp'
  })
  export class SimpleComponent { public text='Hello World!' }

然后一些外部非角度代码块修改 DOM:

let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);

这是一些可能的经过操作后的树:

 <div id="container">
      <h1>My Component</h1>
      <div id="placeholder"></div>
 </div>

所以我想做的就是动态地将 SimpleComoponent 实例添加到 #placeholder div 中。我怎样才能达到这个结果?

我一直在尝试使用 ComponentFactory.createComponent(injector, [], newNode),它虽然添加了组件,但生命周期挂钩和绑定都不起作用。

我相信有某种方法可以使用 ViewContainerRef 来实现这一点,但是如何将它与动态创建的节点链接起来?

这是我期望的结果

 <div id="container">
      <h1>My Component</h1>
      <div id="placeholder">
        <simple-cmp>Hello world!</simple-cmp>
      </div>
 </div>

谢谢!

angular typescript angular2-template
3个回答
44
投票

创建组件时,您可以传递将充当所创建组件的宿主元素的 DOM 节点:

创建(注入器:注入器,projectableNodes?:任何[] [], rootSelectorOrNode?: string|any, ngModule?: NgModuleRef): 组件参考

但是由于该组件不是任何其他组件的子组件,因此您必须手动将其附加到 ApplicationRef 以便获得更改检测。

所以这就是你需要做的:

1) 创建一个组件,指定应添加到的根节点。
2) 将视图附加到 ApplicationRef 以便获得更改检测。您仍然没有

Input
ngOnChanges
操作,但 DOM 更新将正常工作。

  @Component({
      template: `
        <div id="container">
          <h1>My Component</h1>
        </div>
       `,
      selector: 'my-app'
  })
  export class AppComponent { 
      constructor(private resolver: ComponentFactoryResolver,
                  private injector: Injector,
                  private app: ApplicationRef) { 

      }

      addDynamicComponent() {
         let factory = this.resolver.resolveComponentFactory(SimpleComponent);

         let newNode = document.createElement('div');
         newNode.id = 'placeholder';
         document.getElementById('container').appendChild(newNode);

         const ref = factory.create(this.injector, [], newNode);
         this.app.attachView(ref.hostView);
      }
  }

9
投票

永远不要在 Angular 之外修改 DOM,因为这会导致不可预测的行为。即使您手动附加

<simple-cmp>
元素,它也没有任何意义,因为它不是由 Angular 处理的。 Angular 应用程序内对 DOM 的所有更改都必须通过 Angular 方法。

动态创建新组件:

@Component({
    selector: 'my-component',
    template: '<div #element></div>',
})
export class MyComponent {
    @ViewChild('element', {read: ViewContainerRef}) private anchor: ViewContainerRef;

    constructor(private resolver: ComponentFactoryResolver) { }

    whatever() {
        let factory = this.resolver.resolveComponentFactory(ChildComponent);
        this.anchor.createComponent(factory);
    }
}

0
投票

看看我在另一个帖子中对与此主题相关的问题的回答,也许对某人有用。

© www.soinside.com 2019 - 2024. All rights reserved.