简体   繁体   English

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

[英]Angular2: Creating child components programmatically

Question

How to create child components inside a parent component and display them in the view afterwards using Angular2 ? 如何在父组件内创建子组件,然后使用Angular2在视图中显示它们? How to make sure the injectables are injected correctly into the child components? 如何确保将注射剂正确注射到儿童组件中?

Example

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);

Edit 编辑

I found the DynamicComponentLoader in the API docs preview . 我在API文档预览中找到了DynamicComponentLoader But I get the following error when following the example: There is no dynamic component directive at element 0 但是在遵循示例时出现以下错误: 元素0处没有动态组件指令

This is generally not the approach I would take. 这通常不是我采取的方法。 Instead I would rely on databinding against an array that will render out more child components as objects are added to the backing array. 相反,我依赖于对数组的数据绑定,当数组被添加到后备数组时,该数组将呈现更多的子组件。 Essentially child components wrapped in an ng-for 基本上包含在ng-for中的子组件

I have an example here that is similar in that it renders a dynamic list of children. 我在这里有一个类似的例子,它呈现一个动态的子列表。 Not 100% the same, but seems like the concept is still the same: 不是100%相同,但似乎概念仍然是相同的:

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

Warning: DynamicComponentLoader has been deprecated in RC.4 警告:RC.4中已弃用DynamicComponentLoader

In Angular 2.0, loadIntoLocation method of DynamicComponentLoader serve this purpose of creating parent-child relationship. 在Angular 2.0中, DynamicComponentLoader loadIntoLocation方法用于创建父子关系。 By using this approach you can dynamically create relationship between two components. 通过使用此方法,您可以动态创建两个组件之间的关系。

Here is the sample code in which paper is my parent and bulletin is my child component. 以下是示例代码,其中纸张是我的父级, 公告是我的子组件。

paper.component.ts paper.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');

    }
}

bulletin.component.ts bulletin.component.ts

import {Component} from 'angular2/core';

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

paper.html paper.html

<div>
    <div #child></div>
</div>

Few things you needs to be take care of are mentioned in this answer 在这个答案中提到了你需要注意的几件事

You should use ComponentFactoryResolver and ViewElementRef to add component at runtime.Let's have a look at below code. 您应该使用ComponentFactoryResolver和ViewElementRef在运行时添加组件。让我们看看下面的代码。

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

Put the above code inside your ngOnInit function and replace "SpreadSheetComponent" by your component name. 将上面的代码放在ngOnInit函数中,并用组件名称替换“SpreadSheetComponent”。

Hope this will work. 希望这会奏效。

Programmatically add components to DOM in Angular 2/4 app 以编程方式在Angular 2/4 app中向DOM添加组件

We need to use ngAfterContentInit() lifecycle method from AfterContentInit . 我们需要使用ngAfterContentInit()生命周期方法从AfterContentInit It is called after the directive content has been fully initialized. 在指令内容完全初始化后调用它。

In the parent-component.html , add the a div like this: parent-component.html ,添加如下div

<div #container> </div>

The parent-component.ts file looks like this: 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";

  }
}

Inside src\\app\\app.module.ts , add the following entry to the @NgModule() method parameters: src\\app\\app.module.ts ,将以下条目添加到@NgModule()方法参数中:


  entryComponents:[
    childComponent
  ],

Notice that we're not accessing the div#container using the @ViewChild("container") divContainer approach. 请注意,我们没有使用@ViewChild("container") divContainer方法访问div#container We need it's reference instead of the nativeElement . 我们需要它的引用而不是nativeElement We will access it as ViewContainerRef : 我们将以ViewContainerRef访问它:

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

The ViewContainerRef has a method called createComponent() which requires a component factory to be passed as a parameter. ViewContainerRef有一个名为createComponent()的方法,它需要将组件工厂作为参数传递。 For the same, we need to inject a ComponentFactoryResolver . 同样,我们需要注入一个ComponentFactoryResolver It has a method which basically loads a component. 它有一个基本上加载组件的方法。

The right approach depends on the situation you're trying to solve. 正确的方法取决于您尝试解决的情况。

If the number of children is unknown then NgFor is the right approach. 如果孩子的数量未知,那么NgFor是正确的方法。 If it is fixed, as you mentioned, 3 children, you can use the DynamicComponentLoader to load them manually. 如果已修复,如上所述,3个孩子,您可以使用DynamicComponentLoader手动加载它们。 The benefits of manual loading is better control over the elements and a reference to them within the Parent (which can also be gained using templating...) 手动加载的好处是可以更好地控制元素并在Parent中引用它们(也可以使用模板获得...)

If you need to populate the children with data, this can also be done via injection, the Parent is injected with a data object populating the children in place... 如果您需要使用数据填充子项,这也可以通过注入完成,Parent将注入一个填充子项的数据对象...

Again, a lot of options. 再次,很多选择。 I have used 'DynamicComponentLoader' in my modal example, https://github.com/shlomiassaf/angular2-modal 我在我的模态示例中使用了'DynamicComponentLoader', https://github.com/shlomiassaf/angular2-modal

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM