Kalima
Kalima

Reputation: 11

Angular 13: 'AbstractControl.parent is possibly null' while trying to create a custom validator for a FormGroup

I have a form which contains a set of checkboxes and I want to create a custom validator that forces to check at least one of them.

In form.component.ts:


  form: FormGroup = new FormGroup({
    customer: new FormControl('', [Validators.required]),
    partTimeidentification: new FormControl('', [Validators.required]),
    inspectionType: new FormGroup({
      ocr: new FormControl(false, []),
      anomalyDetection: new FormControl(false, []),
      metrics: new FormControl(false, []),
      wiresInspection: new FormControl(false, []),
      other: new FormControl(false, []),
    }, { validators: atLeastOneValidator() }),
    cameraSettings: new FormGroup({
      model: new FormControl('', [Validators.required]),
      size: new FormControl('', [Validators.required]),
      speedOb: new FormControl('', [Validators.required]),
      flashColor: new FormControl('', [Validators.required]),
    }),
  });

In form.component.html (I omitted fields to keep it as clear as possible, you have the structure up here):

 <form class="flex-col text-center" [formGroup]="form!">
     (more fields here)
     <app-box [title]="'Inspection type'" class="text-center me-2" [fit_height]="true" formGroupName="inspectionType">
      <div class="form-check">
       <input class="form-check-input" type="checkbox" formControlName="ocr" name="ocr" value="ocr"/>
       <label class="form-check-label"> OCR </label>
      </div>
      (more checkboxes)
    </app-box>
    (more fields)
    <button [disabled]="!form!.valid" type="button" class="btn bg-primary-tb text-white mt-3 col-4" (click)="submit()">Continue </button>
 </form>

atLeastOneValidator.directive.ts:

import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";

export function atLeastOneValidator(): ValidatorFn {
    return (group: AbstractControl): ValidationErrors | null => {
                let controls = group.parent.controls;
                let theOne = Object.keys(controls).findIndex(key => controls[key].value !== false);
      
                if (theOne) return null;
              
              return { 'atLeastOneRequired': 'At least one should be selected'}
        };

      
};
  

Nevertheless, I keep receiving the error message error TS2531: Object is possibly 'null'. in the validator's group.parent.

To put the validator's code into words: I want to access the parent (what I guess it is inspectionType, a FormGroup) and then look if any of the children (ocr, anomalyDetection... any of those FormControls) are set to true, in that case the form is valid.

Upvotes: 0

Views: 1709

Answers (1)

Mikkel Christensen
Mikkel Christensen

Reputation: 2797

Create a validator which expects a FormGroup and then append the validator to the FormGroup which is the parent to the FormControl of which at least one must be true.

// validator
function atLeastOneValidator() {
  return (control: FormGroup) => {
    const raw = control.getRawValue();
    return Object.keys(raw).map(k => raw[k]).some(_ => _) ? null : {check_one: "Must check at least one"}
  }
}
// form group
  fg: FormGroup;
  constructor(private fb: FormBuilder) {
    this.fg = this.fb.group({
      a: this.fb.control(false),
      b: this.fb.control(false),
      c: this.fb.control(false),
    }, {validators: [atLeastOneValidator()]});
  }

minimal stackblitz: https://stackblitz.com/edit/angular-ivy-f3c3e1?file=src/app/app.component.ts

Upvotes: 1

Related Questions