Angular 8/ Material : subform not showing errors

标签 angular angular-material angular-forms angular-validation

我用这种方式创建了一个带有条件子表单的表单:

在父表单中:

<form [formGroup]="layerFormGroup" (submit)="submit()" #f="ngForm">
  ...
  <div *ngIf="layerFormGroup.value.mode == 'features'">
    <app-edit-layer-features formControlName="modeFormGroup"></app-edit-layer-features>
  </div>

与 TS:

ngOnInit() {

  this.layerFormGroup = this.formBuilder.group({
    ...
    modeFormGroup: ['', Validators.required]
  });
}

public submit() {

  if (!this.layerFormGroup.valid) {
    return;
  }

那么子窗体是:

<ng-container [formGroup]="modeFormGroup">
<mat-horizontal-stepper>

    <mat-step label="Collection" [stepControl]="modeFormGroup">
        <mat-form-field>
            <mat-label>Collection</mat-label>
            <mat-select formControlName="collectionCtrl">
                <mat-option value="col1">col1</mat-option>
                <mat-option value="col2">col2</mat-option>
            </mat-select>
        </mat-form-field>
        <div>
            <button mat-button matStepperNext type="button">Next</button>
        </div>
    </mat-step>

    <mat-step label="Rendered geometry" [stepControl]="modeFormGroup">
        <mat-form-field>
            <mat-label>Rendered geometry</mat-label>
            <mat-select formControlName="geometryCtrl">
                <mat-option value="geoshape">a geopoint</mat-option>
                <mat-option value="geopoint">a geoshape</mat-option>
            </mat-select>
        </mat-form-field>
        <div>
            <button mat-button matStepperNext type="button">Next</button>
        </div>
    </mat-step>

</mat-horizontal-stepper>

最后是 subview :

@Component({
selector: 'app-edit-layer-features',
templateUrl: './edit-layer-features.component.html',
styleUrls: ['./edit-layer-features.component.scss'],
providers: [
  {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => EditLayerFeaturesComponent),
    multi: true
  },
  {
    provide: NG_VALIDATORS,
    useExisting: forwardRef(() => EditLayerFeaturesComponent),
    multi: true
  }
]
})
// ControlValueAccessor: see https://christianlydemann.com/form-validation-with-controlvalueaccessor/
export class EditLayerFeaturesComponent implements OnInit, ControlValueAccessor, Validator {

  public modeFormGroup: FormGroup = this.formBuilder.group({
    collectionCtrl: ['', Validators.required],
    geometryCtrl: ['', Validators.required],
  });

  constructor(
    private formBuilder: FormBuilder) { }

  ngOnInit() {
  }

  public onTouched: () => void = () => { };

  writeValue(obj: any): void {
    if (obj) {
      this.modeFormGroup.patchValue(obj, { emitEvent: false });
      this.onTouched();
    }
  }
  registerOnChange(fn: any): void {
    this.modeFormGroup.valueChanges.subscribe(fn);
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.modeFormGroup.disable() : this.modeFormGroup.enable();
  }
  validate(control: AbstractControl): import('@angular/forms').ValidationErrors {
    return this.modeFormGroup.valid ? null : { invalidForm: { valid: false, message: 'Features fields are invalid' } };
  }
  registerOnValidatorChange?(fn: () => void): void {
    this.modeFormGroup.valueChanges.subscribe(fn);
  }
}

问题如下:当我在父表单中调用submit()方法时,mat-error标签会添加到父表单中,但不会添加到子表单中,即验证错误显示在父表单中,但不显示在子表单中。

经过一些测试,我发现调用

this.modeFormGroup.markAllAsTouched()

在子窗体中确实会显示子错误。无论如何,我应该从父 submit() 方法调用它,但我找不到如何执行此操作 (this.layerFormGroup.get('modeFormGroup').valid不做这项工作)。

我觉得我错过了一些与 Material 相关的东西,有什么线索吗?

谢谢。

编辑1:我创建了一个stackblitz,您可以在其中看到问题:https://stackblitz.com/edit/angular-eldyyc 。如果您仅选择模式=功能并单击保存图层,则仅名称显示为错误,而不是子表单字段

最佳答案

问题在于组件之间的通信以及对原始父表单组的引用。您会看到,您在父组件中使用 modeFormGroup 创建表单组作为没有任何控件的嵌套表单组。然后,您不会将对 layerFormGroup 的引用传递给子组件。

另一方面,在子组件中您创建本地属性modeFormGroup。此 modeFormGrouplayerFormGroup 中的 modeFormGroup 不同。

this.layerFormGroup = this.formBuilder.group({
      name: ['', Validators.required],
      mode: ['', Validators.required],
      id: [''],
      modeFormGroup: this.formBuilder.group({})  //not the same as in the child component
});

请注意,modeFormGroup 是一个空表单组,没有任何控件。现在,在子组件中,您将子表单组创建为:

// totally different form group
public modeFormGroup: FormGroup = this.formBuilder.group({
    collectionCtrl: ['', Validators.required],
    geometryCtrl: ['', Validators.required]
});

您需要做的是,一旦子组件初始化,在 ngOnInit() 函数中使用 EventEmitter 发出创建的表单组,并分配表单组到父表单组中的 modeFormGroup 控件。

我编辑了你的stackblitz

关于 Angular 8/ Material : subform not showing errors,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60258676/

相关文章:

javascript - Angular 6 复选框过滤器覆盖之前的复选框

angular - 如果您还使用 children 参数,请使用 redirectTo,这可能吗?

javascript - Angular:cdkVirtualFor 不呈现新项目

Angular *ngIf 用于嵌套表单组值

javascript - 如何在 Angular 4+ 中从 NgForm 中的 NgModel FormControl 获取 ElementRef 引用

Angular2 - 不能动态更改输入类型

json - Typescript:将 JSON 对象转换为类/接口(interface)对象

html - 列未显示 - 垫表

javascript - 使用 Angular Material 中的日期选择器禁用特定日期

angular - Angular Material 图标中 fontSet 的默认值是多少?