angularangular-reactive-formscustomvalidatorangular-custom-validators

Custom validator with parameter is not working for textbox and checkbox in angular


In my reactive form, I have a textbox and a checkbox. I want that when the checkbox is checked, then textbox can be null or empty. If checkbox is not checked then validation message should be shown for required value. So I have written a custom validator with parameter. But the validator is not working The form code is below:

<form [formGroup]="frmExpenseHead">
  <div class="form-group row">
    <label for="Code" class="col-sm-12 col-form-label">Code</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" [(ngModel)]="txtCode" id="code" name="code" formControlName="code"
        [ngClass]="{ 'is-invalid': submitted && f.code.errors }">
      <div *ngIf="submitted && f.code.errors" class="invalid-feedback">
        <div *ngIf="f.code.errors.conditionRequired">Code is required</div>
      </div>
    </div>

    <div class="col-sm-2 form-check">
      <input class="form-check-input" type="checkbox" [(ngModel)]="chkAutoCode" id="autoCode" name="autoCode"
        formControlName="autoCode">
      <label class="form-check-label" for="autoCode">
        Auto Generate
      </label>
    </div>
  </div>

  <div class="text-center">
    <button class="btn btn-primary mr-1" (click)="onSubmit()">Register</button>
    <button class="btn btn-secondary" type="reset" (click)="onReset()">Cancel</button>
  </div>
</form>

The ts file code is:

@Component({
  selector: 'app-expense-head',
  templateUrl: './expense-head.component.html',
  styleUrls: ['./expense-head.component.css']
})
export class ExpenseHeadComponent implements OnInit {
  frmExpenseHead: FormGroup;
  today = this.calendar.getToday();
  submitted = false;

  txtCode: string;
  chkAutoCode: boolean = false;
  txtDate: NgbDateStruct;
  txtTitle: string;
  txtDescription: string;

  constructor(private calendar: NgbCalendar) { }

  ngOnInit() {    
    this.frmExpenseHead = new FormGroup({
      code: new FormControl("", [conditionalRequired(this.chkAutoCode)]),
      autoCode: new FormControl("")          
    });
  }

  get f() { return this.frmExpenseHead.controls; }

  onSubmit() {
    this.submitted = true;

    if (this.frmExpenseHead.invalid) {
      return;
    }

    alert('SUCCESS!! :-)\n\n' + JSON.stringify(this.frmExpenseHead.value, null, 4));
  }

  onReset() {
    this.submitted = false;
    this.frmExpenseHead.reset();
  }
}

And the custom validator is:

export function conditionalRequired(bValue: boolean): ValidatorFn {  
  return (control: AbstractControl): ValidationErrors | null => {

    let controlValue = control.value;    

    if (bValue === true) {      
      return null;
    }
    
    if (controlValue === "" || controlValue === null || controlValue === undefined) {
      return { "conditionRequired": true }
    }

    return null;
  }
}

Can anybody let me know where is the problem? Please follow the below link for a workable example.

DEMO


Solution

  • You don't have to create a custom validator for that, use the availible tools. It'll be much easier for you.

    You can subscribe to any change of value of your checkbox FormControl and then change and update your input FormControl. Here's an example for you:

    @Component({
      selector: 'app-my',
      templateUrl: './my.component.html',
      styleUrls: ['./my.component.css']
    })
    export class MyComponent implements OnInit {
      public fg: FormGroup;
      public checkbox: FormControl = new FormControl(false);
      public input: FromControl = new FormControl('', Validators.required);
    
      public constructor() { }
    
      public ngOnInit(): void {    
        this.fg = new FormGroup({
          checkbox: this.checkbox,
          input: this.input          
        });
        this.checkbox.valueChanges.subscribe(value => {
          if (value) {
            this.input.setValidators(null);
          } else {
            this.input.setValidators(Validators.required);
          }
          this.input.updateValueAndValidity();
        });
      }
    }