Angular - 如何跟踪 FormGroup 中的数组数组

Angular - How to keep track of array of arrays in a FormGroup

我正在尝试创建一个包含 select 控件列表的表单(只是为了简单起见)。

我不打算向表单添加新的 select,我只想跟踪每个 select 控件中的 selected 选项。 这是我用来生成 select 控件的 json:

    sports = [
    {
      sportId: '1',
      desc: 'Football',
      categories: [
        {
          categId: '1',
          desc: 'U-18'
        },
        {
          categId: '1',
          desc: 'U-20'
        },
        {
          categId: '2',
          desc: 'U-23'
        }
      ]
    },
    {
      sportId: '2',
      desc: 'Volleyball',
      categories: [
        {
          categId: '3',
          desc: 'Junior'
        },
        {
          categId: '4',
          desc: 'Youth'
        }
      ]
    },
    {
      sportId: '3',
      desc: 'Tennis',
      categories: [
        {
          categId: '5',
          desc: 'Singles'
        },
        {
          categId: '6',
          desc: 'Doubles'
        }
      ]
    }
  ];

这是我的表格html

<form [formGroup]="registrationForm"(submit)="save()">
          <div class="form-group">
            <label for="firstname">First Name</label>
            <input
              type="text"
              class="form-control"
              id="firstname"
              formControlName="firstName"
              placeholder="First Name"
            />
          </div>
          <div class="form-group">
            <label for="lastname">Last Name</label>
            <input
              type="text"
              class="form-control"
              formControlName="lastName"
              id="lastname"
              placeholder="Last Name"
            />
          </div>
          <div class="form-group" *ngFor="let sport of sports; let i = index">
            <label attr.for="sport_{{i}}">{{sport.desc}}</label>
            <select class="form-control" id="sport_{{i}}">
                <option value="0">Select one</option>
                <option *ngFor="let cat of sport.categories" [value]="cat.categId">{{cat.desc}}</option>               
              </select>
          </div>
          <button type="submit" class="btn btn-primary">Submit</button>
        </form>

为 firstName 和 lastName 构建表单很简单:

  constructor(private fb: FormBuilder) {}
  ngOnInit(): void {
    this.registrationForm = this.fb.group({
      firstName: '',
      lastName: ''
    });
  }

但我不确定如何跟踪每个不同 select 控件上的 selected 选项。

如果你能在这里帮助我,我将不胜感激。

编辑

这是一个演示

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

您可能使用了错误的结构来生成动态表单控件。 您需要说明您使用的是什么动态控件,如下所示:

profileForm = this.fb.group({
    firstName: ['', Validators.required],
    lastName: [''],
    address: this.fb.group({
      street: [''],
      city: [''],
      state: [''],
      zip: ['']
    }),
    aliases: this.fb.array([
      this.fb.control('') // this states that, there will be dynamic form control array
    ])
  });

然后在读取控件的值后,您可以像下面这样使用;

this.profileForm.get('aliases') as FormArray

您可以在此处从办公网站编辑demo

如果你能提供stackblitz来检查问题,这对那些想回答并直接提供代码更改的人会有帮助。

您要跟踪的每个控件都可以在表单组中有一个条目:

  constructor(private fb: FormBuilder) {}
  ngOnInit(): void {
    this.registrationForm = this.fb.group({
      firstName: '',
      lastName: '',
      // <- Each additional control should be listed here
      football: '', 
      volleyball: '',
      tennis: ''
    });
  }

将表单组视为您要跟踪的一组数据。因此,如果您说您对动态添加运动不感兴趣,只是跟踪它们的值,那么它们的每个值都会成为表单组中的一个条目。

您可以在此处找到 "brute force" 样式的解决方案:https://stackblitz.com/edit/angular-i7ntj3

如果您想动态添加控件(即使您不打算添加更多),您可以使用示例中所示的 FormArray。看起来您主要缺少 [formControlName] 属性 和填充 FormArray 的代码。

组件

  registrationForm: FormGroup;

  get categoryOptions(): FormArray {
    return <FormArray>this.registrationForm.get('options');
  }

  constructor(private fb: FormBuilder) { }

  ngOnInit(): void {
    this.registrationForm = this.fb.group({
      firstName: '',
      lastName: '',
      options: this.fb.array([])
    });

    // Add the sports to the FormArray
    this.sports.forEach(s =>
      this.categoryOptions.push(new FormControl()));
  }

  save() {
    console.log(JSON.stringify(this.registrationForm.value));
  }

注意:FormGroup 需要包含您要跟踪的所有表单控件。在上面的示例中,我们跟踪两个文本字段和一个 FormArray。 FormArray 包含一组表单控件或一组表单组。由于这些表单数组元素是 而不是 动态添加的,因此我们需要手动创建它们。这就是上面代码中 forEach 的目的。

模板

      <div formArrayName="options">
        <div *ngFor="let sport of sports; let i=index">
          <label attr.for="i">{{sport.desc}}</label>
          <select class="form-control" id="i" [formControlName]="i">
            <option value="0">Select one</option>
            <option *ngFor="let cat of sport.categories" [value]="cat.categId">{{cat.desc}}
            </option>
          </select>
        </div>
      </div>

注意:必须将 formArrayName 设置为 FormGroup 中定义的 FormArray 的名称。 ngFor 循环遍历每项运动并设置一个索引,该索引将映射到数组的每个元素。然后将每个 select 元素的 formControlName 设置为数组索引。

您可以在此处找到此 FormArray 解决方案:https://stackblitz.com/edit/angular-reactive-select-deborahk

希望这对您有所帮助。

把你的 ngOnInit() 改成这个。

 ngOnInit(): void {

    this.registrationForm = this.fb.group({ 
      firstName: '0',
      lastName: '0',
      sportsFormArray: this.fb.array([])
    });

    this.sports.forEach((s) => {
      this.sportsFormArray.push(this.fb.control(0));
    });
  }  

而在html中,控制代码的数组将是这样的

<div formArrayName="sportsFormArray">
  <div *ngFor="let sport of sports; let i=index">
    <label>{{sport.desc}}</label>
    <select class="form-control" id="sport_{{i}}" [formControlName]="i">
      <option value="0">Select one</option>
      <option *ngFor="let cat of sport.categories" [value]="cat.categId">{{cat.desc}}</option>              
    </select>
  </div>
</div>