web-dev-qa-db-ja.com

Angular 2 ViewContainerRefを使用せずに、特定のDOMノードにコンポーネントを動的に挿入します

Angular 2 rc5で動的コンポーネントの作成について質問があります。

したがって、2つの単純なangularコンポーネントがあると仮定します。

  @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>

ありがとう!

13

コンポーネントの作成時 作成したコンポーネントのホスト要素として機能するDOMノードを渡すことができます。

create(injector:Injector、projectableNodes ?: any [] []、rootSelectorOrNode ?: string | any、ngModule ?: NgModuleRef):ComponentRef

ただし、このコンポーネントは他のコンポーネントの子ではないため、変更を検出するには、手動で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);
      }
  }

Angularの外ではDOMを変更しないでください。予期しない動作が発生するためです。<simple-cmp>要素を手動で追加しても、Angularによって処理されないため、何の意味もありません。DOM内のすべての変更はAngularアプリは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);
    }
}
7
martin