Reputation: 71
Stackblitz https://stackblitz.com/edit/angular-mh4cox?embed=1&file=src/app/app.component.html
How do I properly show error messages on nested forms? Validation works btw
I tried so many methods here without any luck.
I want it to show an error message on html using ngIF (... invalid && ... touched )
Constructor
constructor(private fb: FormBuilder,private http:HttpClient,private requestService:RequestService) {
this.myForm = this.fb.group({
id:[""],
areaOfInterest: new FormControl("",Validators.required),
status: new FormControl("",Validators.required),
startDate: new FormControl("",Validators.required),
endDate: new FormControl("",Validators.required),
description: new FormControl("",Validators.required),
notes: new FormControl("",Validators.required),
createdBy:"",
updatedBy:"",
resourceDTOS: this.fb.array([]),
});
console.log(this.myForm);
this.getOneRequest(localStorage.getItem('requestId'));
}
This is the nested resource which is a FormArray in this case
addNewResourceDTOS() {
this.control = <FormArray>this.myForm.controls.resourceDTOS;
this.control.push(
this.fb.group({
seniority: this.fb.control(null,Validators.required),
skillDTOS: this.fb.array([this.fb.group({
skill: '' //i dont validate it here
})]),
resourceNotes: this.fb.control(null,Validators.required),
})
);
}
The array skillDTOS
addNewResourceSkill(control) {
control.push(
this.fb.group({
skill: new FormControl("",Validators.required),
}))
}
This is how I'm validating some of my main form variables
get description() {
return this.myForm.get('description');
}
get notes() {
return this.myForm.get('notes');
}
Example html "notes"
<small *ngIf="notes.invalid && notes.touched" class="text-danger">Please enter notes!</small>
It looks something like this
data = {
areaOfInterest:"",
notes:"",
resourceDTOS: [
{
seniority: "",
skillDTOS: [
{
skill: "",
}
],
resourceNotes:""
}
]
}
Is it possible to validate at least seniority/resourceNotes (or skill at best) as well?
Upvotes: 1
Views: 4404
Reputation: 73357
You can simply access validators with hasError()
. So just target the formcontrol you want, usually accessed by myFormgroup.get('formcontrolName')...
So in case of your iteration of skill
you can access the current formcontrol from the defined lines
you have declared for each loop:
<div *ngFor="let lines of resource.get('skillDTOS').controls; let j=index">
<div [formGroupName]="j">
<input formControlName="skill"/>
<div *ngIf="lines.get('skill').touched">
<small *ngIf="lines.get('skill').hasError('required')">REQUIRED</small>
</div>
</div>
</div>
Upvotes: 1
Reputation: 655
In your controller, you can define a new method that would check a particular field's validity based on its and its ancestor indeces. Here's an example for the skill field:
component.ts
isSkillValid(resourceDTOSIndex: number, skillIndex: number): boolean {
const resourceDTOSGroup = this.myForm.controls.resourceDTOS as FormGroup;
const skillDTOSGroup = resourceDTOSGroup.controls[resourceDTOSIndex] as FormGroup;
const skillDTOS = skillDTOSGroup.controls.skillDTOS as FormGroup;
return skillDTOS.controls[skillIndex].valid;
};
component.html
<input
formControlName="skill"
class="form-control"
style="margin-right:5px;"
type="text"
placeholder="Enter skill"
id="skill"
name="skill"
aria-label="button1"
aria-describedby="button1"
/>
<div *ngIf="!isSkillValid(i, j)">
The skill field has no valid value
</div>
I would really suggest you refactor the component and split it into smaller pieces since it's already hard to read and manipulate over it.
Upvotes: 1