Home > other >  Angular ControlValueAccessor how to transfert the invalid status?
Angular ControlValueAccessor how to transfert the invalid status?

Time:09-23

I have created a custom input with ControlValueAccessor I can use it in formControl and it works fine. Now I would like to know when the form control is considered invalid to display a red border on the input inside my custom component.

Here is my custom input:

@Component({
  selector: 'app-input',
  templateUrl: './input.component.html',
  styleUrls: ['./input.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi: true,
      useExisting: InputComponent,
    },
  ],
})
export class InputComponent implements ControlValueAccessor {
  group = new FormGroup({
    input: new FormControl(''),
  });
  touched: boolean = false;

  // The id used for the html
  id!: number;

  // The label of the html input
  @Input() label: string = '';
  @Input() type: string = 'text';

  // The method called when the input is touched
  onTouched = () => {};

  constructor() {
    this.id = Math.floor(Math.random() * 100);
  }
  /**
   * The setter of the input value
   * @param value
   */
  writeValue(value: string): void {
    this.input.setValue(value);
  }

  /**
   * Function to subscribe to changes
   * @param fn
   */
  registerOnChange(fn: any): void {
    this.input.valueChanges.subscribe((value) => {
      fn(value);
    });
  }
  /**
   * Function to subscribe when the input is touched
   * @param fn
   */
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  /**
   * fucntion called to define the input as touched
   */
  markAsTouched() {
    if (!this.touched) {
      this.onTouched();
      this.touched = true;
    }
  }

  /**
   *
   * @param isDisabled
   */
  setDisabledState?(isDisabled: boolean): void {
    if (isDisabled) {
      this.input.disable();
    } else {
      this.input.enable();
    }
  }

  get input() {
    return this.group.get('input') as FormControl;
  }
}

Then I can use it like that.

<app-input
  formControlName="email"
  label="Email"
></app-input>

If my email form control is invalid (because it's not a valid email for example), then there is some class added on my component inside the DOM. enter image description here

Is there a way to get the validity status inside the TS component ?

CodePudding user response:

Instead of providing your value accessor in the decorator with the providers property, use this :

constructor(
  @Optional() @Self() private ngControl: NgControl
) {
  // ...
  if (this.ngControl) this.ngControl.valueAccessor = this;
}

It does the same thing. But what it does MORE, in your case, is to give you access to the native form control with this.ngControl.control.

This means you can get the status of the control at any given point, for instance, you can make this :

get status() {
  return this.ngControl.control.status; // "INVALID", "VALID", "PENDING"
}

CodePudding user response:

you can inject the Injector like this:

export class InputComponent implements OnInit , ControlValueAccessor {

  _control!: NgControl;

  constructor(@Inject(INJECTOR) private injector: Injector) { }

  ngOnInit(): void {
    this._control = this.injector.get(NgControl);
}

and then you can access all control methods - for example:

  get isError() {
    return this._control.control?.invalid;
  }
  • Related