Angular Reactive Form选择选项链接到另一个输入不变

时间:2019-09-11 05:03:24

标签: angular angular-reactive-forms

我想选择一个带有从其他输入中读取的选项的选择,并且当输入更改时,我的选择也将更改。

所有选择和输入均为反应形式。 问题是当我更改输入的值时,仅当我将选项值设置为表单控件时,选择选项才会更新。如果将options的值设置为form control的值,则不会更新它们。

示例代码在这里:https://stackblitz.com/edit/angular-5zfocw

模板:

<form [formGroup]="form">
  <div formArrayName="opts" *ngFor="let opt of form.get('opts').controls; let i = index">
  <div [formGroupName]="i">
    {{i}}:  
    <input type="text" formControlName="name">
  </div>
  </div>
</form>

<form [formGroup]="form">
  <label> Selection:</label>
  <select formControlName="selection">
    <option *ngFor="let opt of form.get('opts').controls; let i=index" [value]="opt.value.name">
      {{opt.value.name}}
    </option>
  </select>
</form>
<hr>

<pre>
 selection: {{ form.get('selection').value | json}}
</pre>

组件:

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  public form: FormGroup
  constructor(private fb: FormBuilder){
    this.form = this.fb.group({
      opts: this.fb.array([
        this.fb.group({name: ['N0']}),
        this.fb.group({name: ['N1']}),
        this.fb.group({name: ['N2']})
      ]),
      selection: [{value: {}}]
    })
  }
}

如果我将HTML模板中的第13行更改为:

<option *ngFor="let opt of form.get('opts').controls; let i=index" [value]="opt">

然后,该选项和输入将完美同步。但是,我无法获得选择的值。

如果将行更改回[value]="opt.value.name",然后选择N2,然后更改N2输入,我的选择将丢失并且该值不会更新。

我想要什么

我想要1.从下拉列表中选择N2。 2.将N2更改为输入中的其他内容,例如N22。 3.选择应更新为N22。 N22值应显示在页面底部。

我该怎么办?

2 个答案:

答案 0 :(得分:3)

您需要检查何时更改数组。为此,请订阅this.form.get('opts')。valueChanges。使用成对获取旧值并更改选择的值。

在代码中,创建表单后

this.form.get('opts').valueChanges.pipe(
  startWith(this.form.value.opts),
  pairwise())
  .subscribe(([old,value])=>{
     const index=old?old.findIndex(x=>x.name==this.form.get('selection').value):-1
     if (index>=0)
        this.form.get('selection').setValue(value[index].name,{emit:false})
  })

stackblitz

更新,如果我们可以删除/添加一些值,则数组也会发生变化。因此,如果删除元素,则需要考虑到。因此,代码变为:

this.form.get('opts').valueChanges.pipe(
  startWith(this.form.value.opts),
  pairwise())
  .subscribe(([old, value]) => {
    if (old.length > value.length) { //if we remove some value
                //we search if "selection" is in the new value
      const index = value? value.findIndex(x => x.name == this.form.get('selection').value) : -1;
      if (index == -1) //if not, simple equal to ""
        this.form.get('selection').setValue("", { emit: false })
    }
    else { //Only change the value if we are not removing
      const index = old ? old.findIndex(x => x.name == this.form.get('selection').value) : -1
      if (index >= 0)
        this.form.get('selection').setValue(value[index].name, { emit: false })
    }
  })

请参阅a new stackblitz

答案 1 :(得分:0)

经过多次尝试和错误后,我想出了另一种解决方案(或解决方法?),只需将其发布在此处以供参考。

我们可以直接使用FormControl作为值,而不是使用字符串值作为选项的值,并且将其连接到输入,因此它们都将同步在一起。

https://stackblitz.com/edit/angular-musy61

HTML文件中的此部分,请参见[ngValue]="opt"

  <select formControlName="selection">
    <option *ngFor="let opt of opts.controls; let i=index" [ngValue]="opt">
      {{opt.value.name}}
    </option>
  </select>

尝试从选择项中选择N2,然后在输入中编辑N2。查看所有内容如何一起更新。

问题在于,当检索出值时,它是一个表单控件。因此,该值很麻烦selection.value.value.name