I want a button to be disabled until a checkbox has been checked using a FormBuilder for Angular. I don\'t want to explicitly check the value of the checkbox and would prefe
.ts
@Component({
selector: 'my-app',
template: `
<h1>LOGIN</h1>
<form [ngFormModel]="loginForm" #fm="ngForm" (submit)="doLogin($event)">
<input type="checkbox" id="cb" ngControl="cb" #cb="ngForm" required>
<button type="submit" [disabled]="!loginForm.valid">Log in</button>
<br/>
<div>Valid ={{cb.valid}}</div>
<div>Pristine ={{cb.pristine}}</div>
<div>Touch ={{cb.touched}}</div>
<div>form.valid?={{loginForm.valid}}</div>
<BR/>
<BR/>
</form>
`,
directives: [ROUTER_DIRECTIVES,FORM_DIRECTIVES,CORE_DIRECTIVES]
})
export class Login {
constructor(fb: FormBuilder) {
this.loginForm = fb.group({
cb: [false, Validators.required],
//cb: ['',Validators.required] - this will also work.
});
}
doLogin(event) {
console.log(this.loginForm);
event.preventDefault();
}
}
Working Plunker.
Please let me know if any changes required.
I found that Validator.required does not work properly for checkboxes. If you check a checkbox and then uncheck it, the FormControl will still show it as valid, even though it is unchecked. I think it only checks that you set it to something, be it true or false.
Here is a quick simple validator you can add to your FormControl:
mustBeChecked(control: FormControl): {[key: string]: string} {
if (!control.value) {
return {mustBeCheckedError: 'Must be checked'};
} else {
return null;
}
}
For Angular 8, I did it like the below for checking if atleast one checkbox is checked amongst three checkboxes
form = new FormGroup({
// ...more form controls...
myCheckboxGroup: new FormGroup({
myCheckbox1: new FormControl(false),
myCheckbox2: new FormControl(false),
myCheckbox3: new FormControl(false),
}, requireCheckboxesToBeCheckedValidator()),
// ...more form controls...
});
created a custom validator
import { FormGroup, ValidatorFn } from '@angular/forms';
export function requireCheckboxesToBeCheckedValidator(minRequired = 1): ValidatorFn {
return function validate (formGroup: FormGroup) {
let checked = 0;
Object.keys(formGroup.controls).forEach(key => {
const control = formGroup.controls[key];
if (control.value === true) {
checked ++;
}
});
if (checked < minRequired) {
return {
requireCheckboxesToBeChecked: true,
};
}
return null;
};
}
and used it like below in html
<ng-container [formGroup]="form">
<!-- ...more form controls... -->
<div class="form-group" formGroupName="myCheckboxGroup">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" formControlName="myCheckbox1" id="myCheckbox1">
<label class="custom-control-label" for="myCheckbox1">Check</label>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" formControlName="myCheckbox2" id="myCheckbox2">
<label class="custom-control-label" for="myCheckbox2">At least</label>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" formControlName="myCheckbox3" id="myCheckbox3">
<label class="custom-control-label" for="myCheckbox3">One</label>
</div>
<div class="invalid-feedback" *ngIf="form.controls['myCheckboxGroup'].errors && form.controls['myCheckboxGroup'].errors.requireCheckboxesToBeChecked">At least one checkbox is required to check</div>
</div>
<!-- ...more form controls... -->
</ng-container>
Create a method to detect any changes
checkValue(event: any) {
this.formulario.patchValue({
checkboxControlName: event.target.checked
})
}
Put that method on an event change and ngModel required
properties
<input (change)="checkValue($event)" type="checkbox" formControlName="checkboxControlName" value="true" ngModel required>
And use the convetional way to validate
this.formulario = new FormGroup({
checkboxControlName: new FormControl('', [Validators.required])
});
Source
HTML Form
<div class="col-md-12">
<div class="form-group">
<input type="checkbox" class="form-check-input" id="agree" formControlName="agree">
<label class="form-check-label" for="agree">
I agree to our <a target="_blank" href="#">Terms of use</a> and
<a target="_blank" href="#">Privacy Policy</a>.
</label>
<div class="text-danger" *ngIf="(isRegSubmit||regForm.get('agree').touched) &&
regForm.get('agree').hasError('required')">
Please agree to terms of use and privacy policy.
</div>
</div>
</div>
TS File
regForm: FormGroup;isRegSubmit: boolean = false;
constructor(
private fb: FormBuilder
}
this.regForm = this.fb.group({
agree : [false, Validators.requiredTrue]
});
Validators.required not worked Also, we can show error message by checking the value too and restrict the user to submit but it is not a good approach as we're not using validation, so whenever there is only a single checkbox then add Validators.requiredTrue instead of Validators.required
Since Angular 2.3.1 you can use Validators#requiredTrue:
Component:
this.formGroup = this.formBuilder.group({
cb: [false, Validators.requiredTrue]
});
Template:
<form [formGroup]="formGroup">
<label><input type="checkbox" formControlName="cb"> Accept it</label>
<div style="color: red; padding-top: 0.2rem" *ngIf="formGroup.hasError('required', 'cb')">
Required
</div>
<hr>
<div>
<button type="submit" [disabled]="formGroup.invalid">Submit</button>
</div>
</form>
STACKBLITZ DEMO