如何找到角度4反应形式的无效控件

时间:2017-07-20 16:11:40

标签: angular angular-reactive-forms reactive

我在Angular中有一个反应形式,如下所示:

this.AddCustomerForm = this.formBuilder.group({
    Firstname: ['', Validators.required],
    Lastname: ['', Validators.required],
    Email: ['', Validators.required, Validators.pattern(this.EMAIL_REGEX)],
    Picture: [''],
    Username: ['', Validators.required],
    Password: ['', Validators.required],
    Address: ['', Validators.required],
    Postcode: ['', Validators.required],
    City: ['', Validators.required],
    Country: ['', Validators.required]
});

createCustomer(currentCustomer: Customer) 
{
    if (!this.AddCustomerForm.valid)
    {
        //some app logic
    }
}

this.AddCustomerForm.valid返回false,但一切看起来都不错。

我试图通过检查控件集合中的status属性来查找。但我想知道是否有办法找到无效的并显示给用户?

14 个答案:

答案 0 :(得分:69)

您可以简单地遍历每个控件并检查状态:

public findInvalidControls() {
    const invalid = [];
    const controls = this.AddCustomerForm.controls;
    for (const name in controls) {
        if (controls[name].invalid) {
            invalid.push(name);
        }
    }
    return invalid;
}

答案 1 :(得分:4)

我刚刚解决了这个问题:每个表单字段都有效,但是表单本身仍然无效。

原来,我在FormArray上设置了“ Validator.required”,在其中动态添加/删除控件。因此,即使FormArray为空,它仍然是必需的,因此即使正确地填充了所有可见控件,表单也始终无效。

我没有找到表单的无效部分,因为我的'findInvalidControls'函数仅检查FormControl,而不检查FormGroup / FormArray。所以我做了一点更新:

/* 
   Returns an array of invalid control/group names, or a zero-length array if 
   no invalid controls/groups where found 
*/
public findInvalidControlsRecursive(formToInvestigate:FormGroup|FormArray):string[] {
    var invalidControls:string[] = [];
    let recursiveFunc = (form:FormGroup|FormArray) => {
      Object.keys(form.controls).forEach(field => { 
        const control = form.get(field);
        if (control.invalid) invalidControls.push(field);
        if (control instanceof FormGroup) {
          recursiveFunc(control);
        } else if (control instanceof FormArray) {
          recursiveFunc(control);
        }        
      });
    }
    recursiveFunc(formToInvestigate);
    return invalidControls;
  }

答案 2 :(得分:3)

在Chrome的DevTools下,选择“控制台”标签。

在控制台提示符下,键入命令:

document.getElementsByClassName('ng-invalid')

输出应与此类似: enter image description here

在这种情况下,带下划线的文本用于格式控件listen-address。带有圆圈的文本.ng-invalid表示该控件无效。

  

注意:已在Chrome中测试

答案 3 :(得分:3)

现在,在角度9中,您可以使用markAllAsTouched()方法显示无效的控件验证器:

this.AddCustomerForm.markAllAsTouched();

答案 4 :(得分:1)

表单和所有控件都扩展了angular类AbstractControl。每个实现都有一个验证错误的访问者。

let errors = this.AddCustomerForm.errors
// errors is an instance of ValidatorErrors

api文档包含所有引用 https://angular.io/api/forms/AbstractControl

修改

我认为错误访问器以这种方式工作但是这个链接到github表明还有一些其他人和我一样的想法 https://github.com/angular/angular/issues/11530

在任何情况下,通过使用控件访问器,您可以迭代表单中的所有formControl。

Object.keys(this.AddCustomerForm.controls)
    .forEach( control => {
        //check each control here
        // if the child is a formGroup or a formArray
        // you may cast it and check it's subcontrols too
     })

答案 5 :(得分:1)

如果表单中没有太多字段,则只需按F12键并将鼠标悬停在控件上,就可以看到带有该字段原始值/触摸值/有效值的弹出式窗口- “#fieldname.form-control.ng-untouched.ng-invalid”。

答案 6 :(得分:1)

尝试

 findInvalidControls(f: FormGroup) {
    const invalid = [];
    const controls = f.controls;
    for (const name in controls) {
      if (controls[name].invalid) {
        invalid.push(name);
      }
    }
    return invalid;
  }

答案 7 :(得分:1)

这将记录所有控件的名称?

for (let el in this.ReactiveForm.controls) {
      if (this.ReactiveForm.controls[el].errors) {
        console.log(el)
      }
 }          

您可以从中创建一个数组或字符串并显示给用户

答案 8 :(得分:1)

就我而言,我禁用了所有表单控件。

这似乎是 Angular 中的一个开放错误:https://github.com/angular/angular/issues/39287

答案 9 :(得分:0)

我自由地改进了 AngularInDepth.com -s代码,以便它也以嵌套形式递归搜索无效输入。它是否由FormArray或FormGroup嵌套。只需输入顶级formGroup,它将返回所有无效的FormControl。

如果您要将FormControl检查和对无效数组功能的添加分开到一个单独的函数中,则可以略去一些“ instanceof”类型的检查。这样会使函数看起来更简洁,但是我需要一个全局的单个函数选项来获取所有无效formControl的平面数组,这就是解决方案!

findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[] {
    if ( ! _invalidControls ) _invalidControls = [];
    if ( _input instanceof FormControl  ) {
        if ( _input.invalid ) _invalidControls.push( _input );
        return _invalidControls;
    }

    if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;

    const controls = _input.controls;
    for (const name in controls) {
        let control = controls[name];
        switch( control.constructor.name )
        {
            case 'AbstractControl':
            case 'FormControl':
                if (control.invalid) _invalidControls.push( control );
                break;

            case 'FormArray':
                (<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
                break;

            case 'FormGroup':
                _invalidControls = findInvalidControls( control, _invalidControls );
                break;
        }
    }

    return _invalidControls;
}

只需那些需要它的人,因此他们不必自己编写代码。

编辑#1

有人要求它还返回无效的FormArray-s和FormGroups,因此,如果您还需要使用此代码,则使用

findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[] {
    if ( ! _invalidControls ) _invalidControls = [];
    if ( _input instanceof FormControl  ) {
        if ( _input.invalid ) _invalidControls.push( _input );
        return _invalidControls;
    }

    if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;

    const controls = _input.controls;
    for (const name in controls) {
        let control = controls[name];
        if (control.invalid) _invalidControls.push( control );
        switch( control.constructor.name )
        {    
            case 'FormArray':
                (<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
                break;

            case 'FormGroup':
                _invalidControls = findInvalidControls( control, _invalidControls );
                break;
        }
    }

    return _invalidControls;
}

答案 10 :(得分:0)

您可以记录格式为console.log(this.addCustomerForm.value)的值,它将控制台所有控件的值,然后null或“”(空)字段表示无效的控件

答案 11 :(得分:0)

解决上述问题的更简洁且不可变的递归版本:

P.S:这两种方法你都需要。

<块引用>

工作测试直到 Angular 11

<块引用>

如果编译器抱怨flatMap,参考这个(Typescript flatMap, flat, flatten doesn't exist on type any[]),不要伪造重启ng serve

findInvalidControls(controls = this.defaultFormGroup.controls) {
    const ctrls = Object.values(controls);
    const names = Object.keys(controls);
    return ctrls.map((a,i) => [a, i])
      .filter(a => (a[0] as FormControl).invalid)
      .flatMap(a => {
        if (a[0] instanceof FormArray) {
          return this.findInvalidArrayControls(a[0].controls);
        } else if (a[0] instanceof FormGroup) {
          return this.findInvalidControls(a[0].controls);
        } else {
          return names[a[1] as number];
        }
      });
  }

  findInvalidArrayControls(controls: AbstractControl[]) {
    const ctrls = Object.values(controls);
    const names = Object.keys(controls);
    return ctrls.map((a,i) => [a, i])
      .filter(a => (a[0] as FormControl).invalid)
      .flatMap(a => {
        if (a[0] instanceof FormArray) {
          return this.findInvalidArrayControls(a[0].controls);
        } else if (a[0] instanceof FormGroup) {
          return this.findInvalidControls(a[0].controls);
        }
         else {
          return names[a[1] as number];
        }
     });
  }

答案 12 :(得分:0)

所以我也反击了这条龙。 就像勇敢的骑士一样,我首先收集了my weapons,阅读了the maps,然后与这头可怕的野兽战斗。

注意

对于复杂的形式或结构,这不是一个可接受的答案,但我发现它适用于简单的形式或结构,没有太多复杂性

代码执行以下操作:

  • 获取表单控件作为数组
  • 循环并检查表单控件是否无效
  • 如果无效,过滤器将包含它
  • 如果有任何无效,结果数组将填充该控件
  • 如果这个结果的长度等于 0,我们可以声明没有控件是无效的,整个表单都是有效的
isFormValid = () :boolean => 
    Object.values(this.form.controls)
        .filter(c => c.invalid).length === 0

// or single lined
isFormValid = () :boolean => Object.values(this.form.controls).filter(c => c.invalid).length === 0

您可以在您想要的地方、提交按钮、提交时或您自己的最佳位置使用它。

答案 13 :(得分:-1)

在html页面中检查表单控件值为空或为空

表单控制值:{{formname.value | json}}