【问题标题】:Angular - How to keep track of array of arrays in a FormGroupAngular - 如何跟踪 FormGroup 中的数组数组
【发布时间】:2019-12-15 05:47:43
【问题描述】:

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

我不会向表单添加新的选择,我只想跟踪每个选择控件中的选定选项。 这是我用来生成选择控件的 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: ''
    });
  }

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

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

编辑

这是一个演示

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

【问题讨论】:

    标签: angular angular-reactive-forms angular-forms formarray


    【解决方案1】:

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

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

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

    您可以在这里找到“蛮力”风格的解决方案: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 循环遍历每项运动并设置一个索引,该索引将映射到数组的每个元素。然后将每个选择元素的formControlName 设置为数组索引。

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

    希望这会有所帮助。

    【讨论】:

    • 谢谢黛博拉。只有最后一件事。我是否必须将索引用作 formControlName?我问这个是因为我想在 FormArray 的每个项目中存储的是这种形状的对象 {: }
    • 目前在 FormArray 中的是一个数字数组。有什么方法可以存储我在之前评论中提到的形状的对象吗?再次感谢黛博拉,你真是太好了
    • 出于什么目的?表单数组中的内容仅跟踪表单的工作方式。您可以将数据存储到与表单数组存储的数据完全不同的数据库中。您将如何在表单数组中使用这些额外信息?
    • 因为这样更容易分辨数组中的数字指的是哪个团队。此外,如果需要跟踪一组输入,而不仅仅是单个选择输入,该怎么办?
    • 谢谢黛博拉,我只需要进行一些更改就可以让它按照我想要的方式工作。结果如下:stackblitz.com/edit/angular-reactive-select-deborahk-xkks2m。现在数组的每个项目都是形状的 FormGroup:{ "teamId": "1", "categId": "3" }。这样,我不仅摆脱了这种“神奇”数字,而且还创建了具有与后端指定的相同结构的数组。再次感谢黛博拉。你真的很有帮助。
    【解决方案2】:

    把你的 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>
    

    【讨论】:

    • 我一定要使用索引作为formControlName吗?我问这个是因为我想在 FormArray 的每个项目中存储的是这种形状的对象 {: } 。目前在 FormArray 中的是一个数字数组。有什么方法可以存储我提到的形状的对象吗?
    【解决方案3】:

    您可能使用错误的结构来生成动态表单控件。 您需要提及您使用的动态控件如下:

    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来检查问题,这将有助于那些想要回答并直接提供代码更改的人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-29
      • 1970-01-01
      • 2018-06-28
      • 2011-07-16
      • 2017-05-15
      • 2014-09-19
      相关资源
      最近更新 更多