1
votes

Using Angular 4, I have a reactive form with check boxes. At least one of the check boxes must be selected in order to submit the form.

I created a custom validation, which seems to be returning the proper value, but the form is always invalid. However, when I check if the form control has error, I get false.

---- Plunker ----

Here is a sample code with the same behavior:

@Component({
  selector: 'my-app',
  providers: [FormBuilder],
  template: `
    <div> 
      Checkbox values: {{alertForm.value | json}}
      <mark> Is Form Valid: {{alertForm.valid}} </mark> <-- WHY IS FORM VALID ALWAYS FALSE?
      Does Fields have error: {{alertForm.get('fields').hasError('checkboxSelected')}}
    </div>

    <form [formGroup]="alertForm">
      <fieldset class="form-group" formGroupName="fields">
        <legend class="col-md-4"> Fields</legend>
        <div class="col-md-8 checkbox column-2">
            <label *ngFor="let type of types.controls; let i=index"> 
              <input name="fieldsAdd" type="checkbox" [formControl]="type" />
                {{fields[i].name}}
            </label>
        </div>
    </fieldset>
    </form> 

  `
})
export class App implements OnInit {
  alertForm: FormGroup;
  fields = [{name:"field1", checked: false}, {name:"field2", checked: false}];

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.alertForm = this.fb.group({
            fields: this.fb.array([], this.checkboxValidator)
        });

    const controlArray = <FormArray>this.alertForm.controls['fields'];
    this.fields.map(field => controlArray.push(this.fb.control(field.checked)));
  }


  checkboxValidator(control: AbstractControl) {
        return { 'checkboxSelected': !(control.value.indexOf(true) >= 0)  };
    }

     get types(): FormArray {
        return this.alertForm.get('fields') as FormArray;
    };

}

---- Plunker ----

Thanks

1

1 Answers

3
votes

The main rule here is that

the validator function takes an Angular control object and returns either null if the control value is valid or a validation error object but you always return object (docs)

{ checkboxSelected: true }

or

{ checkboxSelected: false }

When you check alertForm.get( 'fields').hasError( 'checkboxSelected') angular just do the following match:

return control && control.errors ? control.errors[errorCode] : null;

so it will be correct.

In order to fix the issue you should change your checkboxValidator method as follows:

checkboxValidator(control: AbstractControl) {
  return control.value.indexOf(true) === -1  ? { 'checkboxSelectionError': true } : null ;
}

I also changed error name to a more suitable name.

Example