Angular 2反应形式的嵌套数组? [英] Nested arrays in Angular 2 reactive forms?

查看:92
本文介绍了Angular 2反应形式的嵌套数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下教程在Angular 2中创建反应式表单,效果很好。





首先你需要一些组件( AppComponent 在我的情况下)你声明root FormGroup 。我在下面称它为 trustForm



app.component.ts

  export class AppComponent {
trustForm:FormGroup;

构造函数(私有fb:FormBuilder){}

ngOnInit(){
this.trustForm = this.fb.group({
name: '',
合约:this.fb.array([])
});

this.addContract();
}

initContract(){
返回this.fb.group({
名称:'',
电子邮件:this.fb.array( [])
});
}

addContract(){
const contractArray =< FormArray> this.trustForm.controls ['contracts'];
const newContract = this.initContract();

contractArray.push(newContract);
}

removeContract(idx:number){
const contractsArray =< FormArray> this.trustForm.controls ['contracts'];
contractsArray.removeAt(idx);
}
}

在这个组件中你还有一些方法可以帮到你操纵第一级 FormArray - 合约



app.component.html

 < div class =container> 
< form [formGroup] =trustForm>
< h3>添加信任< / h3>

< div class =form-group>
< label>名称< / label>
< input type =textclass =form-controlformControlName =name>
< / div>

<! - contract - >
< div formArrayName =contracts>
< div * ngFor =let trust of trustForm.controls.contracts.controls; let i = indexclass =panel panel-default>
< div class =panel-heading>
< span>合约{{i + 1}}< / span>
< span class =glyphicon glyphicon-remove pull-right* ngIf =trustForm.controls.contracts.controls.length> 1(click)=removeContract(i)>< /跨度>
< / div>
< div class =panel-body[formGroupName] =i>
< contract [group] =trustForm.controls.contracts.controls [i]>< / contract>
< / div>
< / div>
< / div>
< div class =margin-20>
< button(click)=addContract()class =btn btn-primary>
添加另一份合约+
< / button>
< / div>

< / form>

< h5>详情< / h5>
< pre> {{trustForm.value | json}}< / pre>
< / div>

除了不同的 FormArray之外,与教程中的root html没有什么不同 name。



然后你需要构建类似于 AppComponent 的合约组件



contract.component.ts

  export class ContractComponent {
@Input('group')contractGroup:FormGroup;

构造函数(私有fb:FormBuilder){}

addEmail(){
const emailArray =< FormArray> this.contractGroup.controls ['emailils'] ;
const newEmail = this.initEmail();

emailArray.push(newEmail);
}

removeEmail(idx:number){
const emailArray =< FormArray> this.contractGroup.controls ['emailils'];
emailArray.removeAt(idx);
}

initEmail(){
返回this.fb.group({
text:''
});
}
}

contract.component.html

 < div [formGroup] =contractGroup> 
< div class =form-group>
< label>名称< / label>
< input type =textclass =form-controlformControlName =name>
< / div>

<! - 电子邮件 - >
< div formArrayName =email>
< div * ngFor =let contract of ContractGroup.controls.emails.controls; let i = indexclass =panel panel-default>
< div class =panel-heading>
< span>电子邮件{{i + 1}}< / span>
< span class =glyphicon glyphicon-remove pull-right* ngIf =contractGroup.controls.emails.controls.length> 1(click)=removeEmail(i)>< /跨度>
< / div>
< div class =panel-body[formGroupName] =i>
< email [group] =contractGroup.controls.emails.controls [i]>< / email>
< / div>
< / div>
< / div>
< div class =margin-20>
< button(click)=addEmail()class =btn btn-primary>
添加另一封电子邮件+
< / button>
< / div>

< / div>

如您所见,我们只需更换合约电子邮件 FormArray 我们也将 FormGroup 传递给电子邮件组件



最后,您只需要用所需字段填写 EmailComponent



email.component.ts

  export class EmailComponent {
@Input('group')emailGroup:FormGroup;
}

email.component.html

 < div [formGroup] =emailGroup> 
< div class =form-group>
< label>文字< / label>
< input type =textclass =form-controlformControlName =text>
< / div>
< / div>

您可以在 Plunker示例



如果您认为此解决方案似乎不合适正确,因为父组件包含子组件的描述,如 initContract initEmails ,你可以看看更复杂的



Plunker示例



其中每个组件负责其功能。



如果您正在寻找模板驱动表单的解决方案,请阅读此内容文章:




I have use the following tutorial to create reactive forms in Angular 2 and it works well.

https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2

However, I am now trying to add an array within an array. Using the tutorial above, I have created an 'Organisation' form, which can contain an array of 'Contact' groups. But I am unable to successfully adapt the setup to allow each 'Contact' group to contain an array of 'Email' groups.

I have been unable to find a tutorial or example that covers this and would be grateful for any pointers.

解决方案

Using the tutorial above, I have created an 'Organisation' form, which can contain an array of 'Contact' groups. But I am unable to successfully adapt the setup to allow each 'Contact' group to contain an array of 'Email' groups.

The tutorial above gives you all what you need.

I suppose you want structure like this.

Firstly you need some component (AppComponent in my case) where you declare root FormGroup. I called it trustForm below.

app.component.ts

export class AppComponent {
  trustForm: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.trustForm = this.fb.group({
      name: '',
      contracts: this.fb.array([])
    });

    this.addContract();
  }

  initContract() {
    return this.fb.group({
      name: '',
      emails: this.fb.array([])
    });
  }

  addContract() {
    const contractArray = <FormArray>this.trustForm.controls['contracts'];
    const newContract = this.initContract();

    contractArray.push(newContract);
  }

  removeContract(idx: number) {
    const contractsArray = <FormArray>this.trustForm.controls['contracts'];
    contractsArray.removeAt(idx);
  }
}

In this component you have also some methods that help you to manipulate the first level FormArray - contracts

app.component.html

<div class="container">
    <form [formGroup]="trustForm">
        <h3>Add trust</h3>

        <div class="form-group">
            <label>Name</label>
            <input type="text" class="form-control" formControlName="name">
        </div>

        <!--contracts-->
        <div formArrayName="contracts">
            <div *ngFor="let contract of trustForm.controls.contracts.controls; let i=index" class="panel panel-default">
                <div class="panel-heading">
                    <span>Contract {{i + 1}}</span>
                    <span class="glyphicon glyphicon-remove pull-right" *ngIf="trustForm.controls.contracts.controls.length > 1" (click)="removeContract(i)"></span>
                </div>
                <div class="panel-body" [formGroupName]="i">
                    <contract [group]="trustForm.controls.contracts.controls[i]"></contract>
                </div>
            </div>
        </div>
        <div class="margin-20">
            <button (click)="addContract()" class="btn btn-primary">
                Add another contract +
            </button>
        </div>

    </form>

    <h5>Details</h5>
    <pre>{{ trustForm.value | json }}</pre>
</div>

There is no different from root html from the tutorial except different FormArray name.

Then you need to build contract component that will be similar to AppComponent

contract.component.ts

export class ContractComponent {
    @Input('group') contractGroup: FormGroup;

    constructor(private fb: FormBuilder) { }

    addEmail() {
        const emailArray = <FormArray>this.contractGroup.controls['emails'];
        const newEmail = this.initEmail();

        emailArray.push(newEmail);
    }

    removeEmail(idx: number) {
        const emailArray = <FormArray>this.contractGroup.controls['emails'];
        emailArray.removeAt(idx);
    }

    initEmail() {
        return this.fb.group({
            text: ''
        });
    }
}

contract.component.html

<div [formGroup]="contractGroup">
    <div class="form-group">
        <label>Name</label>
        <input type="text" class="form-control" formControlName="name">
    </div>

    <!--emails-->
    <div formArrayName="emails">
        <div *ngFor="let email of contractGroup.controls.emails.controls; let i=index" class="panel panel-default">
            <div class="panel-heading">
                <span>Email {{i + 1}}</span>
                <span class="glyphicon glyphicon-remove pull-right" *ngIf="contractGroup.controls.emails.controls.length > 1" (click)="removeEmail(i)"></span>
            </div>
            <div class="panel-body" [formGroupName]="i">
                <email [group]="contractGroup.controls.emails.controls[i]"></email>
            </div>
        </div>
    </div>
    <div class="margin-20">
        <button (click)="addEmail()" class="btn btn-primary">
            Add another email +
        </button>
    </div>

</div>

As you can see we just replace contracts to emails FormArray and we are also passing FormGroup to email component

And finally you will only need to fill EmailComponent with desired fields.

email.component.ts

export class EmailComponent {
    @Input('group') emailGroup: FormGroup;
}

email.component.html

<div [formGroup]="emailGroup">
    <div class="form-group">
        <label>Text</label>
        <input type="text" class="form-control" formControlName="text">
    </div>
</div>

Completed version you can find at Plunker Example

If you think that this solution doesn't seems right because the parent component holds the description of the child component like initContract and initEmails you can take a look at more complex

Plunker Example

where each component is responsible for its functionality.

If you're looking for solution for template driven forms read this article:

这篇关于Angular 2反应形式的嵌套数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆