Angular – ControlValueAccessor with Error Validation in Angular Material

angularangular-materialangular-reactive-formsangular8typescript

I am trying to apply Error Validation style with ControlValueAccessor in custom Material Input Textbox. Ever since applying this custom component, all the red border validation status with formControlName/FormBuilders do not show, for required, minlength, etc. It worked natively (out of the box) with Angular Material textbox, until the custom control was applied.

Goal is to have custom textbox working with Form validation. This showed naturally with matInput textbox.

Update:
Posted answer; however not sure if its most efficient one, trying to get Saloo answer working also (if someone can post stackbliz, would be great), open to any more efficient options

enter image description here

Typescript:

import { Component, OnInit, Input, ViewChild, EventEmitter, Output, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-input-textbox',
  templateUrl: './input-textbox.component.html',
  styleUrls: ['./input-textbox.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => InputTextboxComponent),
      multi: true
    }
  ]
})

export class InputTextboxComponent implements OnInit, ControlValueAccessor {
  @Input() MaxLength: string;
  @Input() Value: string;
  @Input() type: string;
  @Input() Label: string;
  @Input() PlaceHolder: string;
  @Output() saveValue = new EventEmitter();
  @Output() onStateChange = new EventEmitter();

  disabled: boolean;

  constructor() { }

  ngOnInit() {
  }

  saveValueAction(e) {
    this.saveValue.emit(e.target.value);
  }

  onChange(e) {
    this.Value = e;
  }

  onTouched() {
    this.onStateChange.emit();
  }

  writeValue(value: any) {
    this.Value = value ? value : '';
  }

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

  registerOnTouched(fn: any) { this.onTouched = fn; }

  setDisabledState(isDisabled) { this.disabled = isDisabled; }
}

HTML:

<div class="input-wrap">
    <mat-form-field appearance="outline">
        <mat-label>{{Label}}</mat-label>   
        <input matInput 
            [attr.maxlength] = "MaxLength"
            [value]="Value ? Value : ''"
            [placeholder]="PlaceHolder ? PlaceHolder : ''"
            [type]="type ? type: 'text'"
            (input)="onChange($event.target.value)"
        >
    </mat-form-field>
</div>

Trying to incorporate this answer with the natural error styling from Angular Material textbox,
Inheriting validation using ControlValueAccessor in Angular

Best Answer

I had the same problem. I tried all and then finally could resolve using this method:

I added this listener on the custom component. You can also do it 'blur' event.

@HostListener('focusout', ['$event.target'])
  onFocusout() {
    this.onTouched();
  }

And also calling onTouched when setting any value.

 writeValue(value: any) {
    this.onTouched();
    this.Value = value ? value : '';
}
Related Topic