响应式表单的输入数组

Array of input on Reactive Forms

我正在努力完成这样的事情

我有一份要订阅的计划列表

{ id: 1, data: '1GB', minsms: '5.000', value: 7.5, simCards: 1 },
{ id: 2, data: '3GB', minsms: '5.000', value: 10, simCards: 3 },
{ id: 3, data: '10GB', minsms: '5.000', value: 15, simCards: 2 },
{ id: 4, data: '20GB', minsms: '5.000', value: 20, simCards: 1 },

客户可以选择每个计划有多少张 SIM 卡,我想进行验证(即使是零卡,客户也需要 select)

我尝试使用 FormArray,但卡住了。有人可以帮助我吗?

代码(为了题我重新写了一个) https://stackblitz.com/edit/angular-ivy-mwvat5

谢谢

已编辑

在 Eliseo 的帮助和指导下,我使用 FormArray 和 FormControl 在 stackblitz 上重写了代码

非常感谢 https://stackblitz.com/edit/angular-ivy-mwvat5

您有一系列计划,并且想要管理一系列“simCards”。由于您只需要 一个 输入,因此您需要一个 FormControls 的 FormArray。

看到你只需要一个数组(**),所以你可以简单定义

simCards:FormArray

您可以在 .ts 中订阅 (*) 以创建 FormArray

plans:any[]
ngOnInit()
{
   this._plansService.getPlans().subscribe(res=>{
     this.plans=res;
     this.simCards=new FormArray(res.map(_=>new FormControl(0)))
   })
}

并创建一个函数来获取 formArray 的控件

  getControl(index)
  {
    return this.simCards.at(index) as FormControl
  }

而你使用

<!--see that iterate over simCards.controls-->
<mat-form-field *ngFor="let control of simCards.controls;let i=index">
<mat-label
  >Num of SIM cards for {{ plans[i].data }} / {{ plans[i].minsms }} at
  {{ plans[i].value | currency: 'EUR' }}</mat-label
>
  <input matInput type="text" [formControl]="getControl(i)" />
</mat-form-field>

注意,simCars 的值只是一个“数字”数组(实际上是字符串),因此,在提交时您需要做一些类似的事情

submit()
{
   const values=this.plans.map((x:any,index:number)=>{
       id:x.id,
       simsCards:this.simCards.value[index]
   })
   this._plansService.save(values)
}

(*)别忘了取消订阅!

您还可以选择创建具有两个属性的 FormGroups 的 formArray:id 和 simsCards。在这种情况下,您可以使用

ngOnInit()
{
   this._plansService.getPlans().subscribe(res=>{
     this.plans=res;
     this.simCards=new FormArray(res.map((x:any)=>new FormGroup({
           id:new FormControl(x.id),
           simCards:new FormControl(0)
          })
     ))
   })
}

你创建函数getGroup

  getGroup(index)
  {
    return this.simCards.at(index) as FormGroup
  }

并使用

<mat-form-field *ngFor="let control of simCards.controls;let i=index" [formGroup]="getGroup(i)">
<mat-label
  >Num of SIM cards for {{ plans[i].data }} / {{ plans[i].minsms }} at
  {{ plans[i].value | currency: 'EUR' }}</mat-label
>
  <input matInput type="text" formControlName="simCards" />
</mat-form-field>

看到了,在这种情况下 this.simCards.value 给我们一个包含 id 和 simCards 的对象数组

最后,如果我们想使用管道异步而不是订阅,我们可以使用“tap”来创建 formArray

ngOnInit(){
    this.plans$ = this._plansService.getPlans().pipe(
      tap((plan: Plan[]) => {
        this.simCards = new FormArray(
          plan.map(
            (x: any) =>
              new FormGroup({
                id: new FormControl(x.id),
                simCards: new FormControl(0),
              })
          )
        );
      })
    );
}

.html和上面的很像

<mat-form-field *ngFor="let plan of plans$ | async;let i=index" [formGroup]="getGroup(i)">
<mat-label
  >Num of SIM cards for {{ plan.data }} / {{ plan.minsms }} at
  {{ plan.value | currency: 'EUR' }}</mat-label
>
  <input matInput type="text" formControlName="simCards" />
</mat-form-field>

注意:你也可以在

中定义一个里面有一个formArray的FormGroup
form=new FormGroup({
   simCards:new FormArray([])
}) 

而且,一如既往,我们使用 FormArray 使用 getter

get simCards()
{
   return this.form.get('simCards') as FormArray
}

这让我们可以避免使用函数 getGroup() 和 getControl() 将 mat-forms 封装在一个表单中

如果 FormControls 的 FormArray

<form [formGroup]="form">
  <div formArrayName="simCards">
    <mat-form-field
      *ngFor="let plan of plans; let i = index" 
    >
      <mat-label>...</mat-label
      >
      <input matInput type="text" [formControlName]="i" />
  </mat-form-field>
  </div>
</form>

ngOnInit()
{
   this._plansService.getPlans().subscribe(res=>{
     this.plans=res;
     this.form=new FormGroup({
       simCards:new FormArray(res.map(_=>new FormControl(0)))
     })
   })
}

如果 FormGroups 的 FormArray

<form [formGroup]="form">
   <div formArrayName="simCards">
    <mat-form-field *ngFor="let control of simCards.controls;let i=index"
       [formGroupName]="i" >
       <label>...</label>
       <input matInput formControlName="simCards" type="text" />
    </mat-form-field>
   </div>
</form>
ngOnInit()
{
   this._plansService.getPlans().subscribe(res=>{
     this.plans=res;
     this.form=new FormGroup({
        simCards:new FormArray(res.map((x:any)=>new FormGroup({
           id:new FormControl(x.id),
           simCards:new FormControl(0)
          })
        ))
     })
   })
}

如果使用管道异步,我们需要将上面的表格包含在 *ngIf 中

<div *ngIf="{ plan: plans$ | async } as data">
  <form [formGroup]="form">
    <div formArrayName="simCards">
      <mat-form-field
        *ngFor="let control of simCards.controls; let i = index"
        [formGroupName]="i"
      >
        <mat-label
          >Num of SIM cards for {{ data.plan[i].data }} /
          {{ data.plan[i].minsms }} at
          {{ data.plan[i].value | currency: 'EUR' }}</mat-label
        >
        <input matInput type="text" formControlName="simCards" />
      </mat-form-field>
    </div>
  </form>
</div>
this.plans$ = this._plansService.getPlans().pipe(
  tap((plan: Plan[]) => {
    this.form=new FormGroup({
      simCards: new FormArray(
        plan.map(
          (x: any) =>
            new FormGroup({
              id: new FormControl(x.id),
              simCards: new FormControl(0),
            })
        )
      )

    })
  })
);