Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setValidators in custom control without from reference in Angular

i have created a custom input control. I don't want to create any custom validation. I want to use default required, minLength, maxLength etc.I know i can do like this

this.form.controls["firstName"].setValidators([Validators.minLength(1), Validators.maxLength(30)]);

but i can't send form reference from parent component. How can i use setValidator inside textbox component.

// input-box.component.ts    
    import { Component, Input, forwardRef } from '@angular/core';
    import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';


    @Component({
      selector: 'app-input-box',
      template:`<label >{{inputdata.label}}</label><br>
      <input type="text" required #textBox [value]="textValue" (keyup)="onChange($event.target.value)" />`,
      styleUrls: ['./input-box.component.less'],
      providers: [
        {
          provide: NG_VALUE_ACCESSOR,
          useExisting: forwardRef(() => InputBoxComponent),
          multi: true
        },
        /*{
          provide: NG_VALIDATORS,
          useExisting: forwardRef(() => InputBoxComponent),
          multi: true,
        }*/]
    })
    export class InputBoxComponent implements ControlValueAccessor {
      @Input() inputdata: any;
      private textValue: any = '';

      onChange(value) {
        this.textValue = value;
        this.propagrateChange(value);
      }

      private propagrateChange = (_: any) => { };

      writeValue(value: any) {
        if (this.inputdata.value) {
          this.textValue = this.inputdata.value;
          this.propagrateChange(this.inputdata.value);
        }

      }

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


      registerOnTouched() { }
    }

use in different component

<app-input-box  name="textBoxParent_{{index}}"  [inputdata]="goaldata"  ngModel ></app-input-box>
like image 671
Pritam Parua Avatar asked Mar 30 '18 16:03

Pritam Parua


People also ask

How will you add validators in form control?

We can add Validators dynamically using the SetValidators or SetAsyncValidators. This method is available to FormControl, FormGroup & FormArray. There are many use cases where it is required to add/remove validators dynamically to a FormControl or FormGroup.

What method should you implement for your custom validator?

Implementing the Validator Interface A Validator implementation must contain a constructor, a set of accessor methods for any attributes on the tag, and a validate method, which overrides the validate method of the Validator interface.

Which method is used to add dynamic validation to the forms in angular?

The FormGroup class exposes an API that enables us to set validators dynamically. We need to listen to optionB value changes and based on that we add or remove the validators we require. We also call the control's updateValueAndValidity() method, as we need to recalculate the value and validation status of the control.

What is the use of updateValueAndValidity?

When you add or remove a validator at run time, you must call updateValueAndValidity() for the new validation to take effect. Adding a validator that already exists will have no effect. If duplicate validator functions are present in the validators array, only the first instance would be added to a form control.


1 Answers

If you want to access the FormControl inside a class that wants to implement the ControlValueAccessor you have to change your usual implementation. You cannot register the class as ControlValueAccessor in the providers array AND inject the FormControl in the constructor. Because the FormControl will try to inject your class, and you will try to inject the control, which will create a circular dependency.

So the changes you need to make are as follows:

  1. Remove NG_VALUE_ACCESSOR and NG_VALIDATORS from the providers array.
  2. Inject NgControl in the constructor and set the control's ControlValueAccessor and Validators.

    constructor(@Self() ngControl: NgControl) { 
       ngControl.valueAccessor = this;
       ngControl.setValidators([Validators.minLength(1), Validators.maxLength(30)]
       ngControl.updateValueAndValidity()
    }
    

If you want to keep the validators specified by the consumer of your custom form component you need to modify the constructor to this:

constructor(@Self() ngControl: NgControl) { 
  const control = ngControl.control;

  let myValidators = [Validators.required, Validators.minLength(5)];
  let validators = control.validator
  ? [control.validator, ...myValidators]
  : myValidators;

  control.setValidators(validators)
  control.updateValueAndValidity();
}

Check out the whole process explained by Kara Erickson (angular core) at AngularConnect 2017. Link

like image 124
Tomasz Kula Avatar answered Sep 30 '22 19:09

Tomasz Kula