1

i am making a custom validator in Angular. the purpose of the validator is that it makes certain fields required when a checkbox is checked. At the moment the input that it validates is always required and not just when the checkbox is checked. here is my validator code:

import { FormControl, AbstractControl } from "../../../node_modules/@angular/forms";

   export function validateCheckbox(control:AbstractControl){
    const val = control.value;
    const check = control.root.get('checkbox'); //i think the problem is here: if i do .value i get an error

    if (check) {
        if (val === null || val === undefined || val === '') {
            return {
                validate: {
                  valid: false
                }
              };
        }else{
            return null;
        }
    }else{
        return null;
    }
}

My component using the validator:

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
import { Customer } from '../account/models/customer.model';
import { validateCheckbox } from './customValidators';


@Component({
  selector: 'caredeal-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.scss'],
  encapsulation: ViewEncapsulation.None
})

export class RegistrationComponent implements OnInit {
  registerForm: FormGroup;

  constructor(private formBuilder: FormBuilder) {
    this.registerForm = this.formBuilder.group({
      name:['',[Validators.required,Validators.minLength(2)]],
      firstName:['',[Validators.required,Validators.minLength(2)]],
      email:['', [Validators.required,Validators.minLength(2)]],
      telephone:['',[Validators.required,Validators.minLength(9)]],
      mobilePhone:['',Validators.minLength(10)],
      type:[''],
      checkbox:[false],
      companyName:['',Validators.minLength(2)],
      rizivNumber:[''],
      taxNumber:['',Validators.minLength(2)],
      streetName:['', Validators.required],
      houseNumber:['',validateCheckbox],
      bus:[''],
      zipCode:['',[Validators.required,Validators.minLength(4)]],
      place:['',[Validators.required,Validators.minLength(2)]]
    })
   }

  ngOnInit() {
  }

}

My html code, the checkbox is at the end of the code, validator is used on housenumber input.

<form [formGroup]="registerForm" (ngSubmit)="onFormSubmit()">
        <div class="container-fluid">
            <h3>Account informatie</h3>
            <div class="row">
                <div class="col-md-6">
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
                        <input type="text" class="form-control" formControlName="name" placeholder="Naam">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
                        <input type="text" class="form-control" formControlName="firstName" placeholder="Voornaam">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-envelope"></i></span>
                        <input type="email" class="form-control" formControlName="email" placeholder="Email">
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-earphone"></i></span>
                        <input type="tel" class="form-control" formControlName="telephone" placeholder="Telefoon">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-earphone"></i></span>
                        <input type="tel" class="form-control" formControlName="mobilePhone" placeholder="GSM">
                    </div>
                    <div class="input-group">
                        <label for="sel1">Type klant:</label>
                        <select class="form-control" formControlName="type">
                            <option>1</option>
                            <option>2</option>
                            <option>3</option>
                            <option>4</option>
                        </select>
                    </div>
                </div>
            </div>
        </div>
        <div class="container-fluid">
            <h3>Bedrijfsgegevens</h3>
            <div class="row">
                <div class="col-xs-12">
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-home"></i></span>
                        <input type="text" class="form-control" formControlName="companyName" placeholder="Bedrijfsnaam">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-home"></i></span>
                        <input type="number" class="form-control"formControlName="rizivNumber" placeholder="RIZIV-nummer">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-home"></i></span>
                        <input type="text" class="form-control" formControlName="taxNumber" placeholder="BTW-nummer">
                    </div>
                </div>
            </div>
        </div>
        <div class="container-fluid">
            <h3>Afleveradres</h3>
            <div class="row">
                <div class="col-xs-12">
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-road"></i></span>
                        <input type="text" class="form-control" formControlName="streetName" placeholder="Straatnaam">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-sound-5-1"></i></span>
                        <input type="number" class="form-control" formControlName="houseNumber" placeholder="Huisnummer">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-inbox"></i></span>
                        <input type="text" class="form-control" formControlName="bus" placeholder="Bus">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-inbox"></i></span>
                        <input type="number" class="form-control" formControlName="zipCode" placeholder="Postcode">
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon"><i class="glyphicon glyphicon-inbox"></i></span>
                        <input type="text" class="form-control" formControlName="place" placeholder="Plaats">
                    </div>
                    <div class="input-group">
                        <input type="checkbox" formControlName="checkbox"  name="">Facturatie adres is verschillend van afleveradres<br>
                    </div>
                    <div class="input-group">
                        <button type="submit" [disabled] = "!registerForm.valid" class="btn btn-primary">Submit</button>
                    </div>
                </div>
            </div>
        </div>

</form>

My Solution

Looks like you don't need a custom validator. it is eassier to subscribe to the checkbox and then update the form according to the value of the checkbox. This is my component code now:

export class RegistrationComponent implements OnInit {
  registerForm: FormGroup;
  bool:boolean = false;
  constructor(private formBuilder: FormBuilder) {
    this.registerForm = this.formBuilder.group({
      name:['',[Validators.required,Validators.minLength(2)]],
      firstName:['',[Validators.required,Validators.minLength(2)]],
      email:['', [Validators.required,Validators.minLength(2)]],
      telephone:['',[Validators.required,Validators.minLength(9)]],
      mobilePhone:['',Validators.minLength(10)],
      type:[''],
      checkbox:[false],
      companyName:['',Validators.minLength(2)],
      rizivNumber:[''],
      taxNumber:['',Validators.minLength(2)],
      streetName:['', Validators.required],
      houseNumber:[''],
      bus:[''],
      zipCode:['',[Validators.required,Validators.minLength(4)]],
      place:['',[Validators.required,Validators.minLength(2)]]
    })
    this.formControlValueChanged();
   }

   setNotification(): void {
    this.bool = !this.bool;
    if(this.bool){
      this.registerForm.root.get('houseNumber').setValidators(Validators.required);
    }else{
      this.registerForm.root.get('houseNumber').clearValidators();
    }
    this.registerForm.get('houseNumber').updateValueAndValidity();
  }

  ngOnInit() {
  }

  formControlValueChanged() {
    this.registerForm.get('checkbox').valueChanges.subscribe(
        (mode: string) => {
            this.setNotification();
        });
}
}
4
  • what error are you getting now? Commented Aug 1, 2018 at 6:17
  • without .value no errors. it's just not working: with .value error: ncaught (in promise): TypeError: Cannot read property 'value' of null TypeError: Cannot read property 'value' of null at FormControl.validateCheckbox [as validator] Commented Aug 1, 2018 at 6:20
  • const check = control.root.get('checkbox:checked'); try with this one. Commented Aug 1, 2018 at 6:41
  • You can't access to anofther form control form custome validator you have to create form group validator Commented Aug 1, 2018 at 7:33

2 Answers 2

1

I did something similar below:

enter image description here

Above I make the phone required only if the Send Notifications radio button is set to text.

I do this using the following code:

  setNotification(notifyVia: string): void {
    const phoneControl = this.customerForm.get('phone');
    if (notifyVia === 'text') {
      phoneControl.setValidators(Validators.required);
    } else {
      phoneControl.clearValidators();
    }
    phoneControl.updateValueAndValidity();
  }

So instead of building a validator, this simply adds or clears the required validator on the field. In my example, I only set the validators for one control (phoneControl), but you could easily set the validators for any number of controls.

This code is called every time the radio button changes using code as shown below. You'd instead need to call the setNotification each time the checkbox is checked:

this.customerForm.get('notification').valueChanges
  .subscribe(value => this.setNotification(value));
Sign up to request clarification or add additional context in comments.

4 Comments

this will solve the problem but clear Validators will clear all others validators on the from control
Where do i set de code where it subscribes to the buttons? Currently trying your solution.
i made some changes to your code, it is working now. thanks for the help! will post my solution for other people to see
@JorenVermeir yes this work for you but formGroup Validator is more cleaner and the place to return validation error rather than set nd clear the validation , this is my point
0

you can't access to another form control from custome validators you have to create a custome form validator

export  function validateCheckbox(fg) {
  if (fg.get('checkbox').value) {
    let val = fg.get('text').value;
    if (val === null || val === undefined || val === '') {
      return {
        validate: {
          valid: false
        }
      };
    } else { // text control has a value
      return null;
    }
  } else { // checkbox value is false 
    return null;
  }
}

component

  form: FormGroup;
  constructor(fb: FormBuilder) {
    this.form = fb.group({
      checkbox: [false],
      text: ['']
    }, { validator: validateCheckbox })
  }

stackblitz example

FormBuilder/Group

1 Comment

But how do i only make the field required when the checkbox is checked?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.