反应表单 - 将字段标记为已触及

Gie*_*šys 47 angular2-forms angular2-formbuilder angular

我无法找到如何将所有表单的字段标记为触摸.主要问题是,如果我不触摸字段并尝试提交表单 - 验证错误未显示.我的控制器中有一段代码占位符.
我的想法很简单:

  1. 用户点击提交按钮
  2. 所有字段标记为触及
  3. 错误格式化程序重新运行并显示验证错误

如果有人知道如何在提交时显示错误,而不实施新方法 - 请分享.谢谢!


我的简化形式:

<form class="form-horizontal" [formGroup]="form" (ngSubmit)="onSubmit(form.value)">
  <input type="text" id="title" class="form-control" formControlName="title">
  <span class="help-block" *ngIf="formErrors.title">{{ formErrors.title }}</span>
  <button>Submit</button>
</form>
Run Code Online (Sandbox Code Playgroud)

而我的控制器:

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

@Component({
  selector   : 'pastebin-root',
  templateUrl: './app.component.html',
  styleUrls  : ['./app.component.css']
})
export class AppComponent implements OnInit {
  form: FormGroup;
  formErrors = {
    'title': ''
  };
  validationMessages = {
    'title': {
      'required': 'Title is required.'
    }
  };

  constructor(private fb: FormBuilder) {
  }

  ngOnInit(): void {
    this.buildForm();
  }

  onSubmit(form: any): void {
    // somehow touch all elements so onValueChanged will generate correct error messages

    this.onValueChanged();
    if (this.form.valid) {
      console.log(form);
    }
  }

  buildForm(): void {
    this.form = this.fb.group({
      'title': ['', Validators.required]
    });
    this.form.valueChanges
      .subscribe(data => this.onValueChanged(data));
  }

  onValueChanged(data?: any) {
    if (!this.form) {
      return;
    }
    const form = this.form;
    for (const field in this.formErrors) {
      if (!this.formErrors.hasOwnProperty(field)) {
        continue;
      }

      // clear previous error message (if any)
      this.formErrors[field] = '';
      const control = form.get(field);
      if (control && control.touched && !control.valid) {
        const messages = this.validationMessages[field];
        for (const key in control.errors) {
          if (!control.errors.hasOwnProperty(key)) {
            continue;
          }
          this.formErrors[field] += messages[key] + ' ';
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

mas*_*wok 107

以下函数通过表单组中的控件进行递归并轻轻触摸它们.因为controls字段是一个对象,所以代码在表单组的控制字段上调用Object.values().

  /**
   * Marks all controls in a form group as touched
   * @param formGroup - The form group to touch
   */
  private markFormGroupTouched(formGroup: FormGroup) {
    (<any>Object).values(formGroup.controls).forEach(control => {
      control.markAsTouched();

      if (control.controls) {
        this.markFormGroupTouched(control);
      }
    });
  }
Run Code Online (Sandbox Code Playgroud)

  • 这可悲不会在Internet Explorer中工作:(简单地改变`(<任何>对象).values(formGroup.controls)``到Object.keys(formGroup.controls).MAP(X => formGroup.controls [X]) `(来自/sf/ask/2998118021/) (13认同)
  • +1在递归部分只是一个小问题.你已经在函数的开头迭代`controls`,所以它应该是以下代码:`if(control.controls){markFormGroupTouched(control); }` (4认同)
  • `touched` 只是意味着输入被模糊了一次。为了使错误出现,我还必须在我的控件上调用 `updateValueAndValidity()`。 (3认同)

hov*_*ado 20

Angular 8中,您可以简单地使用

this.form.markAllAsTouched();
Run Code Online (Sandbox Code Playgroud)

将控件及其后代控件标记为已触摸。

抽象控件文档

  • 如果这似乎不适用于某些控件,则它们可能不在该 FormGroup 中。 (3认同)

Gar*_*One 10

关于@masterwork的答案.我尝试了这个解决方案,但是当函数试图在FormGroup中递归地挖掘时我得到了一个错误,因为在这一行传递了一个FormControl参数,而不是FormGroup:

control.controls.forEach(c => this.markFormGroupTouched(c));

这是我的解决方案

markFormGroupTouched(formGroup: FormGroup) {
 (<any>Object).values(formGroup.controls).forEach(control => {
   if (control.controls) { // control is a FormGroup
     markFormGroupTouched(control);
   } else { // control is a FormControl
     control.markAsTouched();
   }
 });
}
Run Code Online (Sandbox Code Playgroud)


jse*_*rtx 6

循环使用表单控件并将其标记为已触摸也可以:

for(let i in this.form.controls)
    this.form.controls[i].markAsTouched();
Run Code Online (Sandbox Code Playgroud)


yle*_*jen 5

在Angular v8中,您可以借助该markAllAsTouched方法内置此功能。

例如,您可以像

form.markAllAsTouched();
Run Code Online (Sandbox Code Playgroud)

参见官方文档:https : //angular.io/api/forms/AbstractControl#markallastouched