Angular 8 / Материал: подчиненная форма не показывает ошибки - PullRequest
0 голосов
/ 17 февраля 2020

Я создал форму с условной подчиненной формой следующим образом:

В родительской форме:

<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>

и, наконец, дочернее представление:

@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 не выполняет работу).

Мне кажется, что я что-то упустил материал, есть какие-либо подсказки?

Thx.

Редактировать 1: Я создал стек стека, где вы можете увидеть проблему: https://stackblitz.com/edit/angular-eldyyc. Если вы выбираете только режим = Features и нажимаете save layer, то в качестве ошибки отображается только name, а не поля подчиненной формы

1 Ответ

0 голосов
/ 17 февраля 2020

Проблема заключается в связи между компонентами и ссылкой на исходную группу родительских форм. Видите ли, вы создаете группу форм в родительском компоненте с modeFormGroup как вложенную группу форм без каких-либо элементов управления. Тогда вы не передадите ссылку на layerFormGroup дочернему компоненту.

С другой стороны, в дочернем компоненте вы создаете локальное свойство modeFormGroup. Этот modeFormGroup отличается от modeFormGroup в layerFormGroup.

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

...