Angular2:以编程方式创建子组件

时间:2015-06-14 14:29:31

标签: javascript angular typescript

问题

如何在父组件中创建子组件,然后使用 Angular2 在视图中显示它们?如何确保将注射剂正确注射到子组件中?

实施例

import {Component, View, bootstrap} from 'angular2/angular2';
import {ChildComponent} from './ChildComponent';

@Component({
    selector: 'parent'
})
@View({
  template: `
    <div>
      <h1>the children:</h1>
      <!-- ??? three child views shall be inserted here ??? -->
    </div>`,
  directives: [ChildComponent]
})
class ParentComponent {

        children: ChildComponent[];

        constructor() {
            // when creating the children, their constructors
            // shall still be called with the injectables.
            // E.g. constructor(childName:string, additionalInjectable:SomeInjectable)
            children.push(new ChildComponent("Child A"));
            children.push(new ChildComponent("Child B"));
            children.push(new ChildComponent("Child C"));
            // How to create the components correctly?
        }
}
bootstrap(ParentComponent);

修改

我在API docs preview找到了DynamicComponentLoader。但是在关注示例时出现以下错误:元素0处没有动态组件指令

5 个答案:

答案 0 :(得分:18)

这通常不是我采取的方法。相反,我依赖于对数组的数据绑定,当数组被添加到后备数组时,该数组将呈现更多的子组件。基本上包含在ng-for

中的子组件

我在这里有一个类似的例子,它呈现了一个动态的子列表。不是100%相同,但似乎概念仍然是相同的:

http://www.syntaxsuccess.com/viewarticle/recursive-treeview-in-angular-2.0

答案 1 :(得分:11)

警告:RC.4中已弃用DynamicComponentLoader

在Angular 2.0中,loadIntoLocation的{​​{1}}方法用于创建父子关系。通过使用此方法,您可以动态创建两个组件之间的关系。

以下示例代码中 paper 是我的父级,而公告是我的子组件。

paper.component.ts

DynamicComponentLoader

bulletin.component.ts

import {Component,DynamicComponentLoader,ElementRef,Inject,OnInit} from 'angular2/core';
import { BulletinComponent } from './bulletin.component';

@Component({
    selector: 'paper',
    templateUrl: 'app/views/paper.html'

    }
})
export class PaperComponent {
    constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {

    }

    ngOnInit(){
        this.dynamicComponentLoader.loadIntoLocation(BulletinComponent, this.elementRef,'child');

    }
}

paper.html

import {Component} from 'angular2/core';

@Component({
    selector: 'bulletin',
    template: '<div>Hi!</div>'
    }
})
export class BulletinComponent {}

Few things you needs to be take care of are mentioned in this answer

答案 2 :(得分:6)

你应该使用ComponentFactoryResolver和ViewElementRef在运行时添加组件。让我们看看下面的代码。

let factory = this.componentFactoryResolver.resolveComponentFactory(SpreadSheetComponent);
let res = this.viewContainerRef.createComponent(factory);

将上述代码放入ngOnInit函数中并替换&#34; SpreadSheetComponent&#34;按您的组件名称。

希望这会奏效。

答案 3 :(得分:2)

以编程方式将组件添加到Angular 2/4应用程序中的DOM

我们需要使用ngAfterContentInit()中的AfterContentInit生命周期方法。在指令内容完全初始化之后调用它。

parent-component.html中,像这样添加div

<div #container> </div>

parent-component.ts文件如下所示:



class ParentComponent implements AfterContentInit {

  @ViewChild("container", { read: ViewContainerRef }) divContainer

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngAfterContentInit() {
    let childComponentFactory = this.componentFactoryResolver.resolveComponentFactory(childComponent);
    this.divContainer.createComponent(childComponentFactory);
    let childComponentRef = this.divContainer.createComponent(childComponentFactory);
    childComponentRef.instance.someInputValue = "Assigned value";

  }
}

src\app\app.module.ts内,将以下条目添加到@NgModule()方法参数:


  entryComponents:[
    childComponent
  ],

请注意,我们未使用div#container方法访问@ViewChild("container") divContainer。我们需要它的引用而不是nativeElement。我们将以ViewContainerRef

的形式访问它

@ViewChild("container", {read: ViewContainerRef}) divContainer

ViewContainerRef有一个名为createComponent()的方法,它需要将组件工厂作为参数传递。同样,我们需要注入ComponentFactoryResolver。它有一个基本上加载组件的方法。

答案 4 :(得分:1)

正确的方法取决于您尝试解决的情况。

如果孩子的数量未知,那么NgFor是正确的方法。 如果已修复,如上所述,3个孩子,您可以使用DynamicComponentLoader手动加载它们。 手动加载的好处是可以更好地控制元素以及在父元素中对它们的引用(也可以使用模板获得...)

如果您需要使用数据填充子项,这也可以通过注入完成,Parent将注入一个填充子项的数据对象...

同样,很多选择。 我在我的模态示例https://github.com/shlomiassaf/angular2-modal

中使用了'DynamicComponentLoader'