Reputation: 189
I have one reactive form in angular 7 which has three fields email, phone and pager. My requirement is that at least one of them should be filled out by user otherwise we should throw error like this "Please specify one of the notifications (Email, SMS or Pager)."
I have tried writing a custom notification but its not working. Could you please help me that where I am going wrong.
Below is my HTML code:
<form class="form-horizontal" [formGroup]="editorForm">
<div class="form-group" required>
<label for="emailAdressInput">Email Addresses</label>
<input type="text" id="emailAdressInput" formControlName="emailAdresses">
</div>
<div class="form-group" required>
<label for="phoneNumberInput">Email Addresses</label>
<input type="text" id="phoneNumberInput" formControlName="phoneNumber">
</div>
<div class="form-group" required>
<label for="pagerNumberInput">Email Addresses</label>
<input type="text" id="pagerNumberInput" formControlName="pagerNumber">
</div>
</form>
Below is component.ts code:
this.editorForm = this._formBuilder.group({
displayLabel: ['', Validators.required],
emailAdresses: [''],
phoneNumber: [''],
notification: this._formBuilder.group({
pagerNumber: [''],
phoneNumber: [''],
emailAdresses: ['']
}, this.atLeastOneValidator()),
pagerNumber: [''],
});
public atLeastOneValidator = () => {
return (controlGroup) => {
let controls = controlGroup.controls;
if ( controls ) {
let theOne = Object.keys(controls).find(key=> controls[key].value!=='');
if ( !theOne ) {
return {
atLeastOneRequired : {
text : 'At least one should be selected'
}
}
}
}
return null;
};
};
Upvotes: 1
Views: 10969
Reputation: 57981
To indicate validators using formBuilder in a formgroup is adding {validators:yourValidator}
group(controlsConfig: { [key: string]: any; }, options: AbstractControlOptions | { [key: string]: any; } = null)
See in the docs AbstractControlOptions
(if you want to create a formControl, can add the validator directly)
this.editorForm = this._formBuilder.group({
displayLabel: ['', Validators.required],
emailAdresses: [''],
phoneNumber: [''],
notification: this._formBuilder.group({
pagerNumber: [''],
phoneNumber: [''],
emailAdresses: ['']
},{ validators:this.atLeastOneValidator()}), //<--THIS
pagerNumber: [''],
});
}
FutherMore, you forget a <div formGroupName="notification">
in your .html
Anyway, I recomended not use the formBuilder, you can use teh constructor of form group and formControl like
this.editorForm = new FormGroup({
displayLabel: new FormControl('', Validators.required),
emailAdresses: new FormControl(''),
phoneNumber: new FormControl(''),
notification: new FormGroup({
pagerNumber: new FormControl(''),
phoneNumber: new FormControl(''),
emailAdresses: new FormControl('')
},this.atLeastOneValidator()),
pagerNumber: new FormControl(),
});
}
Upvotes: 1
Reputation: 2820
I have solved it in stackblitz : https://stackblitz.com/edit/angular-j3i4yg
export class AppComponent {
name = 'Angular';
editorForm: FormGroup;
// _formBuilder: FormBuilder = new FormBuilder();
constructor(private _formBuilder: FormBuilder) {
this.editorForm = this._formBuilder.group({
displayLabel: ['', Validators.required],
emailAdresses: [''],
phoneNumber: [''],
notification: this._formBuilder.group({
pagerNumber: [''],
phoneNumber: [''],
emailAdresses: ['']
}, { validators: this.atLeastOneValidator }),
pagerNumber: [''],
});
}
public atLeastOneValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
let controls = control.controls;
console.log(controls);
if (controls) {
let theOne = Object.keys(controls).findIndex(key => controls[key].value !== '');
if (theOne === -1) {
console.log(theOne);
return {
atLeastOneRequired: {
text: 'At least one should be selected'
}
}
}
};
}
}
Template :
<form class="form-horizontal" [formGroup]="editorForm">
<fieldset formGroupName="notification">
<div class="form-group" required>
<label for="emailAdressInput">Email Addresses</label>
<input type="text" id="emailAdressInput" formControlName="emailAdresses">
</div>
<div class="form-group" required>
<label for="phoneNumberInput">Email Addresses</label>
<input type="text" id="phoneNumberInput" formControlName="phoneNumber">
</div>
<div class="form-group" required>
<label for="pagerNumberInput">Email Addresses</label>
<input type="text" id="pagerNumberInput" formControlName="pagerNumber">
</div>
</fieldset>
{{editorForm.get('notification')?.errors| json}}
<br>
<br>
<span *ngIf="editorForm.get('notification')?.errors?.atLeastOneRequired"> {{editorForm.get('notification')?.errors?.atLeastOneRequired.text}}</span>
</form>
Check and let me know if you have any doubts.
Upvotes: 3
Reputation:
atLeastOneValue(form: FormGroup): ValidationErrors {
return Object.keys(form.value).some(key => !!form.value[key]) ?
null :
{ atLeastOneRequired : 'At least one should be selected' };
}
And call it through
builder.group({...}, [this.atLeastOneValue]);
Upvotes: 2