Exploring ways to retrieve validation errors for nested formArray controls in Angular 9

In my Angular application, I have implemented a reactive form using the following structure:

this.shipperEditForm = this.fb.group({
  shipperID: [this.shipperId, Validators.required],
  companyAddress: ['', Validators.required],
  companyClassifications: ['', Validators.required],
  companyType: [''],
  poc: this.fb.array([this.createPOC()]),
  paymentTypeId: [''],
  paymentCreditId: [],
  monthlyShipmentId: ['']
})

createPOC() {
 return this.fb.group({
   firstName: ['', Validators.required],
   designation: ['', Validators.required],
   email: ['', Validators.required],
   role: ['', Validators.required],
   phone: ['', Validators.required]
  })
}

get frm1() { return this.shipperEditForm.controls; }
get poc() { return this.frm1.poc as FormArray; }

When it comes to handling validation errors in my template, I am doing it like this:

<div class="row" *ngFor="let pocControl of poc.controls; let i = index">
    <div class="form-row w-100 pl-3 pr-3" [formGroup]="pocControl">
      <div class="col-12 col-lg-4 ">
        <div class="form-group">
          <label>Name</label>
          <input type="text" class="form-control com-input" formControlName="firstName" maxlength="25"
            (keypress)="vs.allowLettersOnly($event)" maxlength="25" [ngClass]="{'is-invalid' : poc.controls[i].get('firstName').errors &&
            (poc.controls[i].get('firstName').errors.touched || poc.controls[i].get('firstName').errors.dirty)}"/>
            <span class="help-block" *ngIf="poc.controls[i].get('firstName').errors &&
            (poc.controls[i].get('firstName').errors.touched || poc.controls[i].get('firstName').errors.dirty)">
              <span *ngIf="poc.controls[i].get('firstName').errors.required" class="text-danger">
                {{constants.errors.required.name}}
              </span>
            </span>
        </div>
      </div>
      <div class="col-12 col-lg-4">
        <div class="form-group">
          <label> </label>
          <button class="btn btn-primary mt-lg-4 border-radius-zero" (click)="addPocItem(i)"
            *ngIf="i === poc.controls.length - 1">+ Add Another POC</button>
          <button class="btn btn-primary mt-lg-4 border-radius-zero" (click)="removePocItem(i)"
            *ngIf="i !== poc.controls.length - 1">- Remove POC</button>
        </div>
      </div>
    </div>
  </div>

However, I have encountered an issue where the "Name" field is not showing the required validation error and is not turning red when there's an error. This indicates that the error is not accessible within the template. How can I solve this and access nested formArray validation errors in my template?

Please note that the provided code snippet does not include the complete form code due to its length.

Answer №1

Exploring all levels is possible by using

this.shipperEditForm.control.get('poc.firstName').valid

Answer №2

The Error object does not have the touched property. It is recommended to use the touched property on the FormControl class.

poc.controls[i].get('firstName').errors.touched ==> poc.controls[i].get('firstName').touched

component.html

<div class="row" *ngFor="let pocControl of poc.controls; let i = index">
    <div class="form-row w-100 pl-3 pr-3" [formGroup]="pocControl">
      <div class="col-12 col-lg-4 ">
        <div class="form-group">
          <label>Name</label>
          <input type="text" class="form-control com-input" formControlName="firstName" maxlength="25"
            (keypress)="vs.allowLettersOnly($event)" maxlength="25" [ngClass]="{'is-invalid' : poc.controls[i].get('firstName').errors &&
            (poc.controls[i].get('firstName').errors.touched || poc.controls[i].get('firstName').errors.dirty)}"/>
            <span class="help-block" *ngIf="poc.controls[i].get('firstName').errors &&
            (poc.controls[i].get('firstName').touched || poc.controls[i].get('firstName').dirty)">
              <span *ngIf="poc.controls[i].get('firstName').errors.required" class="text-danger">
                {{constants.errors.required.name}}
              </span>
            </span>
        </div>
      </div>
      <div class="col-12 col-lg-4">
        <div class="form-group">
          <label> </label>
          <button class="btn btn-primary mt-lg-4 border-radius-zero" (click)="addPocItem(i)"
            *ngIf="i === poc.controls.length - 1">+ Add Another POC</button>
          <button class="btn btn-primary mt-lg-4 border-radius-zero" (click)="removePocItem(i)"
            *ngIf="i !== poc.controls.length - 1">- Remove POC</button>
        </div>
      </div>
    </div>
  </div>

Answer №3

I have found the solution and now it is functioning properly thanks to this code snippet:

<div class="form-group">
   <label>Name</label>
   <input type="text" class="form-control com-input" formControlName="firstName" maxlength="25"
            (keypress)="vs.allowLettersOnly($event)" maxlength="25" [ngClass]="{'is-invalid' : pocControl.get('firstName').errors &&
            (pocControl.get('firstName').touched || pocControl.get('firstName').dirty)}"/>
  <span class="help-block" *ngIf="pocControl.get('firstName').errors &&
            (pocControl.get('firstName').touched || pocControl.get('firstName').dirty)">
     <span *ngIf="pocControl.get('firstName').errors.required" class="text-danger">
                {{constants.errors.required.name}}
     </span>
  </span>
/div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for inputting transition properties in Material UI Popper

Currently, I am making use of material ui popper and I would like to extract the transition into a separate function as illustrated below: import React from 'react'; import { makeStyles, Theme, createStyles } from '@material-ui/core/styles& ...

What is the best way to style an Angular 2 link with a blue color and underline effect?

In my template, I have the following code: <a (click)="delete(book)">Delete</a> Although the link functions properly, it doesn't seem visually appealing. I don't necessarily want it to be blue and underlined, but I'm unsure of ...

Converting an Observable containing an Array of StaffInterface objects to a plain Array of StaffInterface objects in @ngrx/store select

Trying to retrieve an Array<StaffInterface> from an Observable<Array<StaffInterface>> in ngrx store.select. The store.select method returns the Observable<Array<StaffInterface>>, which I then need to convert into an Array<S ...

Creating a factory function for a generic class without repeating the signature

Here is an example code snippet: interface ValueGenerator { next(): any; } class NumberGenerator { next(): number { return 1; } } class ArrayMaker<T extends ValueGenerator> { private generator: T; constructor(valueGene ...

Removing the initial string before an object can be done by utilizing various techniques and

The response I am receiving is in the following format: javax.xml.rpc.ServiceException: [{"ReturnCode":0,"counter":"\\\\sap\\CTI \\CTIConnection"},{"ReturnCode":101,"ErrSt ...

The Relationship between Field and Parameter Types in TypeScript

I am currently working on a versatile component that allows for the creation of tables based on column configurations. Each row in the table is represented by a specific data model: export interface Record { attribute1: string, attribute2: { subAt ...

What is the best way to maintain the order of variadic types for conditionally inferred conditional types?

Here is the type definition that I am working with: type Inner<Type> = Type extends Wrapper<infer U>[] ? U[] : never; Additionally, I have a function with the following signature: function myFunc<From extends Wrapper[], To>( values: ...

The term 'BackgroundGeolocationPlugin' is being used as a value in this context, even though it typically represents a type

I am currently working on an application in Ionic and my goal is to incorporate a background-geolocation plugin using npm. In the past, I had no issues with version 2 of the plugin as it allowed me to import it into NgModule seamlessly. However, due to cer ...

Global Inertia Headers

How can I ensure that a custom header (Accept-Content-Language) is sent with every request, including Inertia manual visits? Below is the code snippet where I define and set the header: import axios from 'axios'; const lang = localStorage.getIt ...

Even after the component is destroyed, the subscription to the service observable continues to emit

I'm facing an issue with an observable in my service. The provided code below demonstrates this: @Injectable({ providedIn: 'root' }) export class MyService { public globalVariable: BehaviorSubject<string> = new BehaviorSubject(&ap ...

The default value for the logged in user in Angular 7 is set to null when

In my login component, I have a form where users can enter their credentials and submit for authentication using the following function: this.auth.login(this.f.email.value, this.f.password.value) .pipe(first()) .subscribe( data ...

Angular 4 is throwing an error because it cannot find the reference to the System object

I integrated angular2-recaptcha into my project from https://github.com/xmaestro/angular2-recaptcha. Here is the snippet I added to my systemjs.config.js: System.config({ map: { 'angular2-recaptcha': 'node_modules/angular2-recaptcha& ...

What is preventing me from being able to spyOn() specific functions within an injected service?

Currently, I am in the process of testing a component that involves calling multiple services. To simulate fake function calls, I have been injecting services and utilizing spyOn(). However, I encountered an issue where calling a specific function on one ...

Highcharts encounters issues with dateRange values disappearing after a refresh in older versions of IE (9 and below) and Chrome

const newCurrentIndex = findIndexForCounter(currentPCData.CounterID, currentPCData.NetworkID); if (currentIndex === newCurrentIndex) { $.each(model.Data, (j, point) => { ...

IntelliJ IDEA does not support the recognition of HTML tags and directives

I seem to have lost the ability to switch between my HTML and TS files in Intellij IDEA; the tags, directives, and autocompletion in HTML are no longer working. Additionally, I'm receiving some warnings: https://i.stack.imgur.com/QjmNk.png Is there ...

Problems with installing ambient typings

I'm having trouble installing some ambient typings on my machine. After upgrading node, it seems like the typings are no longer being found in the dt location. Here is the error message I am encountering: ~/w/r/c/src (master ⚡☡) typings search mo ...

When making a GET request using Angular HttpClient, an error message stating "No overload matches this call" may

One issue I am facing is with a GET method in my backend. When sending a request body as input, I receive a list of results in return. However, the problem arises in my frontend: search(cat: Cat): Observable<Cat[]> { return this.httpClient.ge ...

What is the best approach for implementing line coverage for object literal in Typescript Mocha unit-tests?

Lead: I am a newcomer to using typescript and writing unit tests with Mocha and Chai. Question: Can anyone provide tips on achieving 100% line coverage in unit tests for an object literal that isn't within a class? I want to avoid going static if pos ...

I'm looking to incorporate a module from another component (Next.js, React.js) into my project

I need to implement the "StyledSwiperPagination(swiper-pagination-bullet) at SwiperImages.tsx" in "index.tsx". The problem is that when I added <StyledSwiperPagination /> in index.tsx, nothing appeared on the screen. Lorem ipsum dolor sit amet, co ...

Is there a way to store my Typeorm data source configuration in a separate variable?

I am currently working with NestJS 10 and TypeORM 0.3.17. In my src/config/data-source.ts file, I have the following code snippet... import * as dotenv from 'dotenv'; import * as dotenvExpand from 'dotenv-expand'; import { DataSource } ...