如何以编程方式动态创建angular2中的多个独立组件实例?

时间:2016-10-30 05:00:33

标签: angular

我有一个按钮组件fancy-textbox。我想让用户可以动态添加新的fancy-textbox,但是它们在文本框上方有不同的标签,这些标签基于fancy-textbox本身(或者来自父级)的唯一范围变量所有fancy-textboxes之间未共享的范围变量。我该怎么做呢?目前,我直接在我的模板显示和隐藏中使用它,但我希望能够动态添加更多这个"的实例。编程:

<div *ngIf="showTextBox">
    <fancy-textbox labelForBox="TextBox 1"></fancy-textbox>  
</div>

如果仅在一个特定区域的DOM中创建花式文本框,那就很好。但是,我想要做的是能够在DOM的不同部分动态创建组件。

    <div class="container">
<div class="navsection"><input id="classname" type="text"><button (click)="createFancyButton()">Create Fancy Button</button></div>
    <div class="topsection">
    </div>
    <div class="midsection">
    </div>
    <div class="botsection">
    </div>
<div class="footsection"></div></div>

鉴于上面的模板...假设用户在文本框中输入了类名(例如botsection)并点击了&#34; createfancybutton按钮),我想要&#34;&#34; &#34; <fancy-button></fancy-button>&#34;要放入页面的相应部分,我希望能够动态地创建&#34;独立&#34;花式按钮的实例&#34;在页面模板的不同部分。我可以坚持使用ng-for 3 ng-if语句,但这似乎不切实际。寻找更好的替代方案......

更新:所以步骤将是:

1)用户进入&#34; midsection&#34;进入文本框。 2)用户点击按钮&#34;创建花式按钮&#34; 3) - <fancybutton></fancybutton>组件将添加到div下,类名为#34; midsection&#34; -

用户可以重复点击相同的&#34;创建花式按钮&#34;按钮在此下创建更多。如果用户将输入框更改为&#34; topsection&#34;,那么当用户点击&#34;创建花式按钮&#34;时,fancybutton组件将添加到div下,其中&#34; topsection&#34;。

如果用户输入&#34; newsection&#34;,那么新的div为classname&#34; newsection&#34;将在div下使用classname&#34; container&#34;创建,而fancybutton组件将添加到div中,类名为&#34; newsection&#34;。

5 个答案:

答案 0 :(得分:1)

在组件中添加一系列标签。

使用* ngFor迭代此数组并为每个标签生成一个精美的文本框。

要添加新的花式文本框,请向数组添加新标签。

<fancy-textbox *ngFor="let label of labels" [labelForBox]="label"></fancy-textbox>  

在组件中:

labels: string[] = [];

// to add a fancy textbox:
this.labels.push('new label');

答案 1 :(得分:1)

您需要动态加载组件

这是我的解决方案

<强> Parent.component.ts

import { Component, OnInit, ViewChild, ViewContainerRef, Input, ComponentFactoryResolver, ReflectiveInjector } from
    "@angular/core";

import { FancyButtonCompoent } from "../FancyButton.component";

@Component({
    moduleId: module.id,
    selector: "app-parent",
    templateUrl: "parent.component.html",
    styleUrls: ["parent.component.css"],
    entryComponents: [FancyButtonCompoent]

})
export class ParentCompoent {

    @ViewChild("midsection", { read: ViewContainerRef })
    midsectionContainer: ViewContainerRef;

    constructor(private resolver: ComponentFactoryResolver) {
    }

    createFancyButton() {
        //Name Is Fancybutton data binding property
        var yourdatavalues= {Name:'myname'}
        this.createDynamicbutton({
            input: yourdatavalues,
        });
    }
    //you can add your own model to get what you want like remove,move
     // var dynamiccompoent={Data:yourmodel,compoentcontainer:any}
     //fancybuttonarray:dynamiccompoent[];

 fancybuttonarray:any[];

    createDynamicbutton(elementData) {
        if (!elementData) {
            return;
        }

        // Inputs need to be in the following format to be resolved properly
        let inputProviders = Object.keys(elementData.inputs)
            .map((inputName) => { return { provide: inputName, useValue: elementData.inputs[inputName] }; });
        let resolvedInputs = ReflectiveInjector.resolve(inputProviders);

        // We create an injector out of the data we want to pass down and this components injector
        let injector = ReflectiveInjector
            .fromResolvedProviders(resolvedInputs, this.midsectionContainer.parentInjector);

        // We create a factory out of the component we want to create
        let factory = this.resolver.resolveComponentFactory(DefaultButtonComponent);

        // We create the component using the factory and the injector
        let component = factory.create(injector);

        this.midsectionContainer.insert(component.hostView)

         //your getting every instance of fancy button instance into array
         this.fancybuttonarray.push.(component )

         //if you want to clear elment if you wish
         //this.fancybuttonarray[0].destroy()
          //this.fancybuttonarray[1].destroy()


    }
}

<强> parent.component.html

<div   class="row col-lg-12" >
    <div #midsection >

    </div>
</div>

<强> Fancybutton.compoent.ts

    import { Component, OnInit, Injector } from '@angular/core';


@Component({
    moduleId: module.id,
    selector: 'Fancy-button',
    templateUrl: 'Fancybutton.component.html'
})
export class FancybuttonComponent {

    inputelement:yourDatamodel
    constructor(private injector: Injector) {
        this.inputElement = this.injector.get('inputElement');
    }

}

<强> Fancybutton.compoent.html

    <div>
    <button title="inputelement.Name"(click)r ="alert(inputelement.Name)"></button>
    </div>    

<强>更新

这是关于使用angular2

加载动态子组件的好文章

还可以使用 Plunker example

答案 2 :(得分:1)

从“架构上”看这个,并利用JS / TS OO类继承,我会个人 考虑添加'复合组件'('cc':跟随OO'复合'模式)到每个部分(例如:<top-section-cc-fancytextboxes...></><bot-section-cc-fancytextboxes...></>)。这些用作各种<fancy-textbox>类型的“占位符”,每个cc(复合组件)内可以是零个或多个实例。 现在,每个复合组件从基类/接口组件(例如:<base-section-cc-fancytextboxes>)派生/实现,其中包含管理添加多个<fancy-textbox>类型的基本方法。但是,派生类方法会“知道”在哪里添加正确的<fancy-textbox> s(可能是*ngFor'd数组,如上所述)。至于实例化特定类型的<fancy-textbox>,也许利用类工厂模式也很有用 - 可能是一个AJ2服务提供者,它返回实例并由复合组件驱动。

无论如何,使用AJ2内置的TS OO,尽管有详细信息,但这是个人将用于解决此特定问题的向量。这只是一个想法。

答案 3 :(得分:1)

我认为您不需要任何其他范围/组件。这样的事情应该有效。

组件(TypeScript):

sections: {[key] : string[]} = {};

createFancyButton: (section: string) => {
    if (!this.sections[section]) {
        this.sections[section] = [];
    }
    this.sections[section].push('');
}

getSectionKeys: () => {
    return Object.keys(this.sections);
}

“sections”属性是一个可索引对象,这意味着它的行为类似于哈希表。 sections对象的每个属性(“key”)都是一个字符串数组,表示花哨的按钮值(ngModel)。

模板(HTML)

<div class="container">
    <div class="navsection">
        <input #section type="text" placeholder="section" />
        <button (click)="createFancyButton(#section.value)">Create Fancy Button</button>
    </div>
    <div *ngFor="let key of getSectionKeys()" [class]="key">
        <fancy-textbox *ngFor="let textBox of sections[key]" [(ngModel)]="textBox"></fancy-textbox>
    </div>
</div>

有一个模板引用变量(#section),可以方便地访问模板中的DOM元素。然后我们* ngFor来自部分哈希表的键来创建每个部分div。最后,我们* ng对每个部分的字符串数组。

有关模板参考变量的更多信息,请点击此处。 https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ref-vars

注意:可能存在拼写错误,因为我没有对此进行测试。

答案 4 :(得分:0)

这是以编程方式构建和添加组件的方式:

type
  TWebBrowser = class(SHDocVw.TWebBrowser)
  protected
    procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
  end;

procedure TWebBrowser.WMGetDlgCode(var Msg: TWMGetDlgCode);
begin
  inherited;
  Msg.Result := Msg.Result or DLGC_WANTARROWS;
end;