【问题标题】:Unable to validate Angular 6 this.fb.array无法验证 Angular 6 this.fb.array
【发布时间】:2019-06-21 15:19:42
【问题描述】:

我想对我的复选框 FormBuilder.array 实施验证,但尽管选中了其中一​​个框,表单仍然无效。

我尝试了Validators.requiredValidators.requiredTrue,但仍然无法按预期工作

TS:

this.Form = this.fb.group({
  stage: this.fb.array([], Validators.required)
})

HTML:

<div class="form-check-label">
  <label class="checkbox-inline">
    <input type="checkbox" class="checkbox" name="none" value="1" #noneChk
      (change)="onCheckArray($event, Form.value.stage)">
    Stage 1
  </label>
</div>
<div class="form-check-label">
  <label class="checkbox-inline">
    <input type="checkbox" class="checkbox" name="self" value="2" #selfChk
      (change)="onCheckArray($event, Form.value.stage)">
    Stage 2
  </label>
</div>

<p>{{ this.Form.valid | json }}</p>

我有我的 StackBlitz here

【问题讨论】:

  • Mhfour,Validators.required 在 formArray 中不起作用,因为 FormArray 的值始终是“某物”-一个数组-。您需要制作一个自定义验证器来检查是否检查了 formArray 的一个元素
  • 要理解一个复选框,请检查stackblitz的这个问题。 stackoverflow.com/questions/56619632/…。注意:如果您想使用自定义表单控件,但不想使用材质,只需将复选框列表组件中的 &lt;mat-checkbox [formControl]="check"&gt;{{key?_data[i][text]:_data[i]}}&lt;/mat-checkbox&gt; 替换为 &lt;label&gt;&lt;input type="checkbox" [formControl]="check"&gt;{{key?_data[i][text]:_data[i]}}&lt;/label&gt;
  • 是否有自定义验证的示例?我尝试了一些,但没有成功
  • 我添加了一个答案来制作自定义验证器。

标签: angular typescript


【解决方案1】:

关于你的 stackblitz,我 forked your stackblitz

问题是你的函数 onCheckArray 没有改变 FormArray(是的,你改变了值,但没有改变 FormArray,所以有任何验证。查看你的函数编辑

//I repite the getter stage, so the answer can be understood

get stage(): FormArray {
  return this.Form.get('stage') as FormArray;
}

onCheckArray(event) { //you needn't send the value
    /* Selected */
    if (event.target.checked) {
      // Add a new control in the arrayForm, 
      // use push, but add a new FormControl TO the formArray
      this.stage.push(new FormControl(event.target.value));
    } else {
      /* unselected */
      // find the unselected element
      let i: number = 0;

       //we iterate over the formArray
      for (i = 0; i < this.stage.value.length; i++) {
        if (this.stage.value[i] == event.target.value) {
          //use removeAt(i)
          this.stage.removeAt(i);
          return;
        }
      }
    }
  }

嗯,你的函数验证器可以更简单,只需检查数组的长度

minSelectedCheckboxes(min = 1) {
    return (formArray: FormArray) => {
      return formArray.controls.length >= min ? null : { required: true };
    };

}

如果初始化FormArray会有问题

this.Form = this.fb.group({
  stage: this.fb.array([new FormControl("3")], this.minSelectedCheckboxes())
})

你的 .html 必须是这样的

 <div class="form-check-label">
    <label class="checkbox-inline">
      <input type="checkbox" class="checkbox" name="none" value="1" #noneChk 
          <!--see how indicate when is checked-->
          [checked]="stage.value.indexOf('1')>=0"
           (change)="onCheckArray($event)">
      1
    </label>
  </div>

好吧,我问的是一种更简单的方法来管理一组复选框,我们可以采取另一种方法。我们的 FormArray 将是一个值为真/假的控件数组,我们有一个函数可以将这个数组转换为我们的值。

  options=["1","2","3","4"]; //our options
  get valuesSelected() ; //a function that return the options selected
  {
      return this.options.filter((x,index)=>this.newForm.get('stage').value[index])
  }
  //see how create the formArray, always has the same number of 
  //elements that our options

  this.newForm=new FormGroup({
        stage:new FormArray(this.options
             .map(x=>new FormControl(false)),this.minTrueCheckboxes())
  })

  minTrueCheckboxes(min = 1) {
    return (formArray: FormArray) => {
      return formArray.value.filter(x=>x).length>=min? null : { required: true };
    };
  }

我们的 .html 变得像

<form class="form" [formGroup]="newForm" (ngSubmit)="onSubmit()">
  <div formArrayName="stage">
    <label class="checkbox-inline" *ngFor="let control of newForm.get('stage').controls;let i=index">
      <input type="checkbox" class="checkbox" [formControl]="control" >
          {{options[i]}}
    </label>
  </div>
</form>

<p>{{ valuesSelected | json }}</p>

【讨论】:

  • 非常感谢它现在可以工作了!只是想知道,如果我希望复选框默认为空,我该怎么做?我从 fb.array 中的 formControl 中删除了值 3,但初始值为 null,如何使其为空?
  • stage: this.fb.array([], this.minSelectedCheckboxes()),只是一个空数组
【解决方案2】:

可以在自己的组件中制作自定义验证器 或外面。

你可以在this stackblitz看到这两个模型

//In the own component
this.form = new FormGroup({
      checks: new FormArray([
        new FormControl(true),
        new FormControl(false),
      ], this.AtLeatOne()), //sii that call it as this.AtLeastOne
    });

AtLeatOne() {
    return (control: FormArray) => {
      if (control.value.find(x => x))
        return null
      return { "error": "You must select at least one option" }
    }
  }

//OutSide
    this.form2 = new FormGroup({
      checks: new FormArray([
        new FormControl(true),
        new FormControl(false),
      ], AtLeatOneValidator())
    });

export function AtLeatOneValidator()
{
  return (control: FormArray)=> {
      if (control.value.find(x => x))
        return null
      return { "error": "You must select at least one option" }
  }
}

好吧,如果我们想向函数发送参数,我提出了最一般的情况(假设我们希望用户至少选择 2 个选项。)

【讨论】:

  • 嗨,我试过了,但无法正常工作。就我而言,我使用 Form.value.whateverControlName 并将其用作数组。是否有可以应用于此的自定义验证器?
  • @mhfour,我在您的 .html 中看不到表格。如果您想查看示例,请查看我的答案的 stackblitz,并使用 .html 更新您的问题
  • 嗨,我刚刚将我的 stackblitz 添加到我的问题中。非常感谢您的帮助
猜你喜欢
  • 2019-10-30
  • 2019-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多