Binding FormControl validators to a custom form Material Select component

荒凉一梦 提交于 2020-02-06 08:01:09

问题


I have this stackblitz set up by way of an example.

I have a standard input form field and a custom field that shows a select bound to an array.

<form [formGroup]="formGroup">
    <mat-form-field class="field">
      <mat-label>City</mat-label>
      <input matInput placeholder="City" formControlName="address1" />
    </mat-form-field>

    <app-dataset-select label="Country" [items]="countries" formControlName="countryId"></app-dataset-select>

</form>

The whole thing is wrapped by a form with validation:

 this.formGroup = new FormGroup({
    address1: new FormControl(model.address1, Validators.required),
    countryId: new FormControl(model.countryId, Validators.required)
  });

When I click SAVE I expect both fields to visibly show validation - the FormGroup itself says we do.

But the Country control does not get the ng-invalid state (and thus no redness) and I'm not sure why - although its something to do with angular's reactive forms kung-fu black magic...


回答1:


well, if we want an "asterisk" when required, one way to do it is that our mat-input was add [required] attribute to our inner input

<mat-select ... [required]="isRequired?true:null">

How give value to isRequired variable?

Well, I like use in constructor and ask about if there are an attribute(*)

  constructor(@Attribute('required') required, public injector: Injector) {
    this.isRequired=required!=undefined
  }

And we use our custom component like

<app-custom-select placeholder="My State" formControlName="state" 
     [optionList]="stateList" required>
</app-custom-select>

In that case we can not included the Validators.required

A forked stackblitz that include the * if required

(*) we can use a simple @Input too, but @Input must be used only if we want change the value dinamically




回答2:


Big thanks to @Eliseo but that solution was not working for me on my existing code (different way of binding, Angular 8?) and I was getting even more frustrated - ngControl.control was always undefined..

The solution does not require a custom ErrorStateMatcher apparently, but the answer is to ensure the mat-select is bound to the FormControl in the FormGroup which is fiddly due to life-cycle events, but effectively:

export class DatasetSelectComponent extends AbstractFormFieldComponent {
  @Input() label!: string;
  @Input() items!: [{id: number, label: string}];
}

export abstract class AbstractFormFieldComponent implements  ControlValueAccessor {

  // tslint:disable-next-line:variable-name
  _formControl = new FormControl(); 
  onChange = (value: any) => {};

 constructor(@Self() @Optional() public ngControl: NgControl) {
      if(this.ngControl) {
        this.ngControl.valueAccessor = this;
      }
    }
  ngAfterViewInit(): void {
    if (this.ngControl) {
      setTimeout(() => {
        this.formControl = this.ngControl.control as FormControl;
        console.log(this.ngControl, this.ngControl.control);
      })
    }
  }

  get formControl() :FormControl|RequiredFormControl {
    return this._formControl;
  }
  set formControl(forControl:FormControl|RequiredFormControl)  {
    this._formControl = forControl;
  }

  registerOnChange(fn: (value: any) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: (value: any) => void): void {}

  writeValue(value: any): void {
    if(this.formControl) this.formControl.setValue(value, { emitEvent: false });
  }


}

Note the removal of the component injection of NG_VALUE_ACCESSOR (replaced by the workings in the constructor), which prevents a cyclical dependency compile-time error:

providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi: true,
      useExisting: forwardRef(() => CustomSelectComponent),
    }
  ]

And a snippet from the template:

  <mat-select [formControl]="formControl" [required]="formControl.required">
    <mat-option *ngFor="let item of items" [value]="item.id">
      {{ item.label }}
    </mat-option>
  </mat-select>

Updated blitz



来源:https://stackoverflow.com/questions/60062444/binding-formcontrol-validators-to-a-custom-form-material-select-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!