0

Am working on angular project where I need to submit a form with some values where the exams

form fields are dynamically created when I click the add button each row() will be added in the form.

for adding each exam values. I could delete each row as well in the form.

The requirement is I need to display a validation message for subject, mark and exams for each dynamic row created on click submit button if it is invalid/not selected. The exams field is a multiple checkbox list validate if nothing is selected

<form [formGroup] = "SettingsForm" (ngSubmit) = "SettingsFormSubmit()">
    <div class="row">
      <div class="col-xl-4">
        <input type="text" placeholder="Name" formControlName="Name">
      </div>
    <div class="row">
      <div class="col-xl-4 ">
        <p *ngIf="submitted && SettingsForm.get('Name').invalid class="text-danger">
          Name is required.
        </p>
      </div>
    </div>
    <div class="row">
      <div class="col-xl-12">
        <table class="table" formArrayName="PersonalData">
          <thead>
            <tr>
              <th>Subject</th>
              <th>Mark</th>
              <th>Exams</th>
              <th>Delete</th>
              <th><button type="button"  (click)="addPersonalData()" class="btn-blank">Add</button></th>
            </tr>
          </thead>
          <tbody>
            <tr [hidden]="!data.value.active"   *ngFor="let data of PersonalData().controls;let i=index" [formGroupName]="i">
              <td>
                <select class="form-control" formControlName="subject"  >
                  <option>Select Subject</option>
                  <ng-container *ngFor="let subject of subjects">
                  <option  value="{{ subject.id }}" >{{ subject.subject_name }}</option>
                  </ng-container>
                </select>
                <ng-container *ngIf="data.get(subject).invalid">
                  <span class="">error message</span>
                </ng-container>
              </td>
              <td>
                <select class="form-control" formControlName="mark">   
                  <option>Select Mark</option>
                  <option>50</option>
                  <option>60</option>
                  <option>90</option>
                </select>
                <ng-container *ngIf="data.get(mark).invalid">
                  <span class="">error message</span>
                </ng-container>
              </td>
              <td>
                <mat-form-field>
                  <mat-label>Select Exams</mat-label>
                  <mat-select  #examsSelect multiple formControlName="exams" >
                    <mat-option (click)="examsSelect()" *ngFor="let term of terms" [value]="term.id">
                      {{term.name}}
                    </mat-option>
                  </mat-select>
                </mat-form-field>
                  <ng-container *ngIf="data.get(exams).invalid">
                  <span class="">error message</span>
                </ng-container>
              </td>
              <td><button type="button"  (click)="deletedata(i)" >Delete</button>
              </td>
              <td><button type="button"  (click)="addPersonalData()" >Add</button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <div class="modal-footer">
      <button type="submit" class="btn btn-success">Submit</button>
    </div>
   </form> 



   this.SettingsForm = this.formBuilder.group({
    id: [''], 
    Name: ['',Validators.required],
    PersonalData: this.formBuilder.array([this.formBuilder.control('', Validators.required)])
   });


  PersonalData() : FormArray {
    return this.SettingsForm.get("PersonalData") as FormArray
  }

  newPersonalData(): FormGroup {
    return this.formBuilder.group({
      id: '',
      subject: '',
      mark: '',
     exams: '',
   })
  }

  addPersonalData() {
    this.PersonalData().push(this.newPersonalData());
  }

Iam saving each PersonalData to the formbuilder dynamically so at a time suppose if I have added 3 rows added then a group of 3 form fields will be their as formarray with same formcontrolname how to validate and show error messages for all the dynamically generated form fields? I got error when I do so..

`ERROR TypeError: Cannot read properties of null (reading 'invalid')`
22
  • You are adding form control this.formBuilder.array([this.formBuilder.control at initial stage. But afterwards you are pushing formgroup inside array? Commented Oct 8, 2021 at 15:55
  • When you iterate array your first control is formcontrol not formgroup so at that point he is not going to get any subject or mark, so the null error Commented Oct 8, 2021 at 16:02
  • 1
    This ` data.get(subject).invalid` should be data.get('subject').invalid.. inverted comma missing ..same for others Commented Oct 8, 2021 at 16:29
  • 1
    We can do it. Just add <option value="">Select Mark</option> and mark: ['', Validators.required], stackblitz.com/edit/… Commented Oct 9, 2021 at 20:10
  • 1
    share it on stackblitz Commented Oct 9, 2021 at 21:21

2 Answers 2

2

Form initialized as

this.SettingsForm = this.formBuilder.group({
  id: [null],
  Name: [null, Validators.required],
  PersonalData: this.formBuilder.array([]),
});

Add validation for each dynamic field as

  newPersonalData(): FormGroup {
    return this.formBuilder.group({
      id: '',
      subject: [null, Validators.required],
      mark: [null, Validators.required],
      exams: [null, Validators.required],
    });
  }

There no field with name active so commented it

// [hidden]="!data.value.active"
<tr
*ngFor="let data of PersonalData().controls; let i = index"
[formGroupName]="i"
>

To do validation encode control name in inverted comma

<ng-container *ngIf="data.get('subject').invalid">

Sample Demo

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for sharing, let me try this , but i was already doing this <ng-container *ngIf="data.get('subject').invalid"> before getting the error i have mentioned. But may be it is because of some other reason i guess it might be because of the the validators needed for each fields in formgroup!
Please don't forget to mark the answer as accepted and upvote, if it solved your issue
yeah sure, could you please get any reference of applying CSS for dynamically added mat field in my scenario? Thanks!
It's not the problem with mat-select. I would say you should either use mat-select or normal select for all dropdowns.
0

You can call your formControlName.errors to check if there is an error in it directly in your html like so *ngIf="name.errors?.required" (for a Validators.required case). You can then display a message like: "This value is required".

It can also be called in the component.ts to validate forms before sending data.

Enjoy coding!

4 Comments

Thanks for helping out, am saving each PersonalData to the formbuilder dynamically so at a time suppose i have added 3 rows then a group of 3 for fields will be their as formarray with same formcontrolname how to validate and show error messages for all the dynamically generated form fields? i got error when i do so.. ERROR TypeError: Cannot read properties of null (reading 'invalid')
You need to create separate components for your lines, this way you will isolate the forms from each other and the validations will be easier to perform and replicate.
Yeah , thanks for the suggestion but looking forward to validate the fields in same form!
Change your formControlName maybe? so they do not have the same name?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.