【问题标题】:Reactive forms: mark dirty all controls in form group反应式表单:将表单组中的所有控件标记为脏
【发布时间】:2019-07-23 09:43:59
【问题描述】:

我有带有表单的 Angular 6 应用程序。这是一个例子

export class ExampleComponent implements OnInit {
    form: FormGroup;

    constructor(private fb: FormBuilder) { }

    ngOnInit() {
        this.form = new FormGroup({
            first: new FormControl(),
            last: new FormControl()
        });

        this.markControlsAsDirty(this.form);
    }

    markControlsAsDirty(form: FormGroup) {
        this.form.get('first').markAsDirty();
        this.form.get('last').markAsDirty();
    }
}

我不想获得单个控件并标记每个字段。 我可以将表单组中的所有控件都标记为脏吗?

更新我已被添加 stackblitz example 以表明之前的两个答案是错误的

【问题讨论】:

    标签: angular typescript angular-reactive-forms


    【解决方案1】:

    当前版本 (12) 在 abstractControl 上有 markAllAsTouched 但没有 markAllAsDirty。

    这是我将所有 formControls 设置为脏的示例:

    export function markAllAbstractDirty<T extends AbstractControl>(control: T): void {
      if (control instanceof FormGroup) {
        const controls = control.controls;
    
        Object.keys(controls).forEach(key => {
          controls[key].markAsDirty();
          markAllAbstractDirty(controls[key]);
        });
      } else if (control instanceof FormArray) {
        control.controls.forEach(formControl => formControl.markAsDirty());
      } else if (control instanceof FormControl) {
        control.markAsDirty();
      } else {
        throw new Error('Error: unexpected control value');
      }
    }
    

    【讨论】:

      【解决方案2】:

      Sachin Gupta 解决方案的简化版本:

      public static markAllControlsAsDirty(abstractControls: AbstractControl[]): void {
          abstractControls.forEach(abstractControl => {
            if (abstractControl instanceof FormControl) {
              (abstractControl as FormControl).markAsDirty({onlySelf: true});
            } else if (abstractControl instanceof FormGroup) {
              this.markAllControlsAsDirty(Object.values((abstractControl as FormGroup).controls));
            } else if (abstractControl instanceof FormArray) {
              this.markAllControlsAsDirty((abstractControl as FormArray).controls);
            }
          });
        }
      

      并像这样使用它:

      FormUtils.markAllControlsAsDirty(Object.values(this.form.controls));
      

      【讨论】:

        【解决方案3】:

        在 FormGroup 中标记为脏控件(只有那些有值的控件)

        markDirtyAllControlsWithValue(form: FormGroup): void {
          const recursiveFunc = (formGroup: FormGroup) => {
            Object.keys(formGroup.controls).forEach(field => {
              const control = formGroup.get(field);
              if (control.value !== null && control.value !== undefined && control.value !== '') {
                control.markAsDirty();
              }
              if (control instanceof FormGroup) {
                recursiveFunc(control);
              }
            });
          };
          recursiveFunc(form);
        }
        

        【讨论】:

          【解决方案4】:

          如果你有一个复杂的表单结构,你可以隔离代码来标记FormGroupFormArrayFormControl为脏。请参阅此处的示例:Mark Form as dirty

          markDirty() {
          this.markGroupDirty(this.form);
          console.log('FORM:', this.form);}
          markGroupDirty(formGroup: FormGroup) {
          Object.keys(formGroup.controls).forEach(key => {
            switch (formGroup.get(key).constructor.name) {
              case "FormGroup":
                this.markGroupDirty(formGroup.get(key) as FormGroup);
                break;
              case "FormArray":
                this.markArrayDirty(formGroup.get(key) as FormArray);
                break;
              case "FormControl":
                this.markControlDirty(formGroup.get(key) as FormControl);
                break;
            }
          });
          }
          markArrayDirty(formArray: FormArray) {
          formArray.controls.forEach(control => {
            switch (control.constructor.name) {
              case "FormGroup":
                this.markGroupDirty(control as FormGroup);
                break;
              case "FormArray":
                this.markArrayDirty(control as FormArray);
                break;
              case "FormControl":
                this.markControlDirty(control as FormControl);
                break;
            }
           });
          }
          markControlDirty(formControl: FormControl) {
               formControl.markAsDirty();
          }
          

          【讨论】:

          • 很好的解决方案,但我确实想指出,在生产构建中,构造函数名称将更改/被丑化。最好做一个 if/else if 块来检查它是否是类的instaceof
          【解决方案5】:

          最佳做法:

          这会使每个控件变脏:this.form.markAsDirty();

          使用这种方式(第二种选择):

          let controls = this.form.controls;
          
              controls.forEach(control => {
                    this.form.get(control).markAsDirty();
                  });
          

          【讨论】:

          • 控件仍然不脏,但表单有
          【解决方案6】:

          要么将整个 formGroup 标记为脏:

          this.form.markAsDirty();

          或标记每个字段:

          Object.keys(this.form.controls).forEach(key => { this.form.get(key).markAsDirty(); });

          【讨论】:

          • 1 选项:控件仍然是原始的,但表单很脏 2 选项:linter 错误“控件在抽象控件类型上不存在”
          • 1 option: controls still pristine but form is dirty 这就是您所要求的。 2 option: linter error "control does not exist on type Abstract control"if (control instanceof FormControl)
          • 我问过Can I mark all controls in form group as dirty?。结果不是我预期的
          • 我在stackblitz中添加了示例,您可以在问题更新中看到。
          • 更新了答案。
          猜你喜欢
          • 2018-09-21
          • 1970-01-01
          • 1970-01-01
          • 2016-10-14
          • 2021-12-04
          • 1970-01-01
          • 2021-03-15
          • 1970-01-01
          • 2017-03-24
          相关资源
          最近更新 更多