What is the best way to customize a div depending on the validation status of all reactive form fields within it?

I am facing a challenge with a rather complex form that contains multiple fields. Some of these fields are used to create logical blocks, and I would like to emphasize the surrounding div if any of these included fields are invalid. Can you suggest the best approach to accomplish this?

Currently, I have been attempting the following implementation, but I seem to be stuck at a certain point

import { Component } from '@angular/core';
import {FormBuilder, Validators} from "@angular/forms";

@Component({
  selector: 'app-root',
  template: `
    <form [formGroup]="form">
      <input formControlName="name">
      <div class="div-address" [class.div-error]="DivHasError(divAddress)" #divAddress>
        <div class="div-text">Address</div>
        <input formControlName="addressType">
        <div formGroupName="address">
          <div>
            <input formControlName="street">
          </div>
          <div>
            <input formControlName="city">
          </div>
        </div>
      </div>
    </form>
  `,
  styles: [
    `
      input.ng-invalid {border-color: red;}
      .div-error .div-text {color: red;}
    `
  ]

})
export class AppComponent {
  protected form = this.fb.group({
    name: ['', Validators.required],
    addressType: ['office', Validators.required],
    address: this.fb.group({
      street: ['', Validators.required],
      city: ['', Validators.required],
    })
  });
  constructor(private fb: FormBuilder) {
  }

  DivHasError(divElement: HTMLDivElement): boolean {
    //TODO: Implement a more generic way to determine if any of the included fields are valid
    // Return True if any included field is invalid, otherwise False
    ???
  }
}

I am seeking a generic solution that does not involve manually listing all the fields in the "DivHasError" method. What would be the most efficient approach to achieve this?

Answer №1

Why not simplify things?

Anytime a field is invalid, Angular will automatically add the ng-invalid class to it. So all you need to do is list them in your CSS file.

For more information on form validation in Angular, check out this resource and learn about Control status CSS classes.

Answer №2

After carefully analyzing the issue, I came up with a simple solution. Here's a handy function that can verify if any fields within the div contain invalid data:

function CheckFormControls(form: FormGroup, elements:Element[], path: string[], controls: AbstractControl[]) {
  for (let child of elements) {
    const formGroupName = child.getAttribute('formGroupName');
    const formControlName = child.getAttribute('formControlName');
    const fieldPath = formGroupName ? [...path, formGroupName] : path;
    if (formControlName) {
      const field = form.get([...fieldPath, formControlName]);
      if (field) {
        controls.push(field)
      }
    }
    if (child.children.length > 0) {
      CheckFormControls(form, Array.from(child.children), fieldPath, controls);
    }
  }
}

export function ValidateDiv(formGroup: FormGroup, div:HTMLDivElement): boolean {
  const controls: AbstractControl[] = [];
  CheckFormControls(formGroup, Array.from(div.children), [], controls);
  for (let control of controls) {
    if (!control.valid) {
      return true;
    }
  }
  return false;
}

As for the HTML part:

<div class="div-address" [class.div-error]="ValidateDiv(form, divAddress)" #divAddress>

I do have some concerns about performance given the complexity of the validation logic, but at first glance, it seems acceptable.

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

Challenges with Angular 4 service initialization

Having trouble with my authentication service. The constructor is being called 259 times when making an HTTP request, but only once when the call is removed. I am using a shared module to provide a unique instance of the service. Angular version: 4.4.4 C ...

Encountering an Angular 13 ChunkLoadError during application deployment, despite the presence of the respective chunk

We encountered an issue with our application's upgrade from Angular 11 to 13. While running 'ng serve' on the local machine works fine, deploying it to our Azure app service causes the lazy loaded modules to fail loading. The specific error ...

Steps for sending a POST request for every file in the given array

I am working on an angular component that contains an array of drag'n'dropped files. My goal is to make a POST request to http://some.url for each file in the array. Here is what I have been attempting: drop.component.ts public drop(event) { ...

Does adjusting the background transparency in IE8 for a TD result in border removal?

I attempted to create a JSFiddle, but it was not coming together as expected. My goal is to change the color of table cells when hovered over. I have been trying to adjust the opacity of the background color for this effect, but I encountered some strange ...

Strategies to prevent fortuitous success in testing

I have the following test case: it('is to display a welcome message', () => { spyOnProperty(authServiceSpy, 'token').and.returnValue(environment.testAuthenticationToken); let teacher: Teacher = authServiceSpy.token.teacher; ...

The size of the cursor varies depending on the line it's placed on

I have a content editable div where three lines are separated by BR tags. When I click on the second line, the cursor becomes bigger than that in the first line. .content { line-height: 35px; } <div class="content" contenteditable="true"> ...

The chosen option from the dropdown menu fails to register as selected

In my Angular 8 application, I am facing an issue with a dropdown list. The data for the dropdown list is fetched from the backend. However, when I select a value from the dropdown list, it remains undefined or not selected. Interestingly, if I manually ...

Issues with hidden overflow and height attributes not functioning correctly in Internet Explorer 9 when using the DOCTYPE HTML standards mode

I have a <div> with overflow:hidden and height:100% that adjusts the div contents to fit the window's height on Chrome and Safari. However, in IE9, the div does not respect the styles of overflow:hidden and height:100%, causing it to expand to ...

Dynamically scrolling an element using jQuery without specifying specific values

I need to keep an element fixed when scrolling on a page without setting specific height values. Do you know of any way to achieve this? Below is the code for reference: // Keep the orange box at the top after scrolling to a certain extent $(window).sc ...

Combining several JSON objects into a single JSON object using JavaScript

I am in need of merging JSON objects from various sources into a single JSON object using JavaScript. For example, I have two JSON objects with different values that I need to combine and add a new value to the final result. json1= { "b":"t ...

Tips on how to select only the currently active tab and change its background color

I am currently troubleshooting the AJAX tabs functionality on my website. The issue I am facing is that the current code does not apply any styling to indicate an active tab. I believe I may need to use some JavaScript code to address this problem, but I ...

DevExpress popup remains contained within the iframe and does not overflow beyond its boundaries

My dilemma involves incorporating a FilterControl within an iframe popup. My issue arises when using the column selector (or any other DevExpress combobox), as the popup remains confined within the frame without extending beyond its borders. I am seeking a ...

The custom styling in custom.css is not taking precedence over the styles defined in

My site is experiencing some element overwriting when I include css/bootstrap.min.css, such as 'a' tags, the .nav bar, and fonts used on the site. Load order: <link href="css/bootstrap.min.css" rel="stylesheet"/> <link rel="styleshe ...

Can the default position of the scrollbar be set to remain at the bottom?

I have a select option tag with a scrollbar to view the contents in the dropdown. I am looking for a way to automatically position the scroll at the bottom when an item is selected from the dropdown. jquery code $('document').ready(func ...

Child component is not rendering *ngIf despite using @Import property

I am currently working with the shared-components module. This module is exported by the app.module and then imported into the module where I intend to use it. Within the shared-components module, there is a component that should render based on three *ngI ...

Click to dynamically toggle classes with jQuery

I am trying to apply a class called 'select' when I click on a paragraph tag. However, the code I have written doesn't seem to be working. Can someone please provide some suggestions? Here is the code: <style type="text/css"> #el ...

Tips for improving the performance of your Ionic 2 app

Recently, I've been working on enhancing the performance of my Ionic 2 App, particularly focusing on optimizing page loading speed. After closely analyzing the timeline of page transitions using Chrome Dev Tools, it became evident that the bottleneck ...

Angular's HTTP client allows developers to easily make requests to

I am struggling with grasping the concept of async angular http client. In my Java backend, I have endpoints that return data in the same format but with different meanings. To handle this, I created the following code: export class AppComponent implement ...

Utilize the :not() selector in combination with the :first-child() selector

Currently, I am seeking a method to merge two css selectors together in order to target specific elements. The selectors I am attempting to combine are ':not' and ':first-of-type'. Here is the code snippet that represents my current sit ...

Exploring for JSON keys to find corresponding objects in an array and adding them to the table

I'm currently working on a project where I need to extract specific objects from a JSON based on an array and then display this data in a table. Here's how my situation looks: playerIDs: number[] = [ 1000, 1002, 1004 ] The JSON data that I am t ...