Require that the parent FormGroup is marked as invalid unless all nested FormGroups are deemed valid - Implementing a custom

Currently, I am working on an Angular 7 project that involves dynamically generating forms. The structure consists of a parent FormGroup with nested FormGroups of different types.

My goal is to have the parentForm marked as invalid until all of the nested/subforms are valid (although my ultimate aim is to have them submitted, but I'm not there yet).

this.parentForm = new FormGroup(this.subforms, { validators: allSubModulesValidValidator }); 

The subforms object looks like this:

interface DynamicKeyFormGroup {
  [key: string]: FormGroup;
}

subforms: DynamicKeyFormGroup = {};

I am aware that my validator implementation is incorrect, and I am struggling with designing a validator for a FormGroup as opposed to a FormControl.

The concept is to iterate through all the properties of this.subForms, which represent the nested FormGroups, and check their status. If any are found to be invalid, the parentForm should also be marked as invalid.

const allSubModulesValidValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
  const controls = control.controls;
  for (const key in controls) {
    if (controls.hasOwnProperty(key)) {
      if (!(controls[key].status === 'valid')) {
        return { 'allSubModulesValid': true };
      }
    }
  }
  return null;
};

In response to a comment, even after removing the validator, the parent form is considered valid while the child remains invalid: https://i.stack.imgur.com/pK19C.png

Answer №1

In my view, this appears to be a bug within Angular, although as discussed in the earlier comments, clearValidators behavior is intentional.

Let's delve into what exactly is going on here.

From what I gather, based on the image, it seems like you are clearing the validators using either of the following methods:

someControl.validator = null;

This approach may not be entirely appropriate, or by directly invoking the clear validators function, for instance:

someControl.clearValidators()

According to the Angular source code snippet provided below:

/**
   * Empties out the synchronous validator list.
   *
   * When you add or remove a validator at run time, you must call
   * `updateValueAndValidity()` for the new validation to take effect.
   *
   */
  clearValidators(): void {
    this.validator = null;
  }

as shown in the mentioned GithubSource link.

The issue lies in the fact that clearing the status does not trigger an update for the control and its parent elements.

To rectify this behavior post-clearing the status, you should update the control with:

someControl.clearValidators();
someControl.updateValueAndValidity();

updateValueAndValidity will effectively refresh the control's current state and inform the relevant FormGroup if applicable.

Referencing @jb-nizet's example in the previous comments: stackBlitz showcases a solution that functions properly even after validator clearance by utilizing the setValue method of the control, which internally triggers updateValueAndValidity.

override setValue(value: TValue, options: {
        onlySelf?: boolean,
        emitEvent?: boolean,
        emitModelToViewChange?: boolean,
        emitViewToModelChange?: boolean
      } = {}): void {
        (this as {value: TValue}).value = this._pendingValue = value;
        if (this._onChange.length && options.emitModelToViewChange !== false) {
          this._onChange.forEach(
              (changeFn) => changeFn(this.value, options.emitViewToModelChange !== false));
        }
        this.updateValueAndValidity(options);
      }

This can be observed in the Angular Source file, where updateValueAndValidity is internally invoked to update the state.

Captain speaking from experience three years later :D

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

The Gatsby + Typescript project is reporting that the module with the name "*.module.scss" does not have any exported members

I've recently gone through Gatsby's demo project in their documentation (which is long overdue for an update). I've carefully followed the instructions provided here: I've included an index.d.ts file in the /src directory of my project ...

Leveraging both the value from getStaticProps and the parameter in the component within NextJS

With this code snippet, I am attempting to load markdown files from a specific directory and pass them to a component that will display one of the markdown files based on a specified parameter. However, I am encountering an error when trying to use the com ...

Preventing the automatic selection of the initial item in a PrimeNG dropdown menu

While utilizing the p-menu component from PrimeNG in popup mode ([popup]="true"), I encountered an unexpected issue where the first item in the menu is automatically selected and turns gray. Here is the code snippet that I am using: <p-menu #menu [popu ...

What is the proper way to declare the "any" module in TypeScript?

I am currently in the process of migrating a large project from JavaScript to TypeScript, taking it step by step. So far, I have converted one of the files to TypeScript, but the other files can contain any content at the moment. For example, something l ...

Troubleshooting IONIC 4: Task failed to execute the dex archive transformation with external libraries merger for the debug version

I need help with my ionic 4 app development. I keep encountering an error whenever I try to build the android app. FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:transformDexArchiveWithExternalLibsDexMerg ...

Having trouble getting a constructor to function properly when passing a parameter in

Here's the code snippet I'm working with: import {Component, OnInit} from '@angular/core'; import {FirebaseListObservable, FirebaseObjectObservable, AngularFireDatabase} from 'angularfire2/database-deprecated'; import {Item} ...

The object might be undefined; TypeScript; Object

Why is it that the object may be undefined, even though it is hard-coded in my file as a constant that never changes? I've tried using ts-ignore without success. const expressConfig = { app: { PORT: 3000, standardResponse: `Server ...

What is the best way to bring attention to a field that is outside the current viewport?

Is there a way to automatically scroll to the specific invalid field after clicking on submit in a large form, without having to manually search for it by scrolling through the page? ...

Angular styling and form error issue

Hey there! I'm new to Angular and facing a major issue along with a minor styling problem. Let's start with the big one: <mat-form-field appearance="fill"> <mat-label>Password</mat-label> <input matInput ...

Arrange two input fields side by side if the quantity of input fields is unspecified

I am currently in the process of developing a project using Angular. I have implemented an *ngFor loop to dynamically add input fields based on the data retrieved from the backend. Is there a way I can ensure that two input fields are displayed on the same ...

Issue arising with data exchange between components using data service in Angular 5

Utilizing data service to share information between components has presented a challenge for me. References: Angular: Updating UI from child component to parent component Methods for Sharing Data Between Angular Components Despite attempting the logic o ...

Next.js is failing to infer types from getServerSideProps to NextPage

It seems like the data type specified in getServerSideProps is not being correctly passed to the page. Here is the defined model: export type TypeUser = { _id?: Types.ObjectId; name: string; email: string; image: string; emailVerified: null; p ...

Struggling to incorporate Dependency Injection into Angular 4

I have a class defined as shown below: import { Injectable, Inject } from '@angular/core'; @Injectable() export class MovieIndustry { constructor(private music: MusicIndustry) { } producer() { this.music.album(); al ...

What steps can be taken to resolve the Angular error stating that the property 'bankCode' is not found on type 'User' while attempting to bind it to ng model?

I'm encountering an issue with my application involving fetching values from MongoDB and displaying them in an Angular table. I've created a user class with properties like name and password, but I keep getting errors saying that the property doe ...

Leverage the power of Filesaver.js in conjunction with Angular

I've searched through all the articles I could find about integrating Filesaver JS with Angular, but I'm still struggling to find a solution that works for me. In my system.config.js file, I included the following code in the map section: ' ...

Setting various colors for different plots within a single chart: A step-by-step guide

I'm currently tackling a project that requires me to showcase two different plots on the same chart, one being a "SPLINE" and the other a "COLUMN". My aim is to assign distinct background colors to each of these plots. Please note that I am referring ...

What is the best approach for promoting reusability in Angular: creating a new CSS class or a new component?

I have a div with a set of CSS properties that are essential to my application. These properties will be reused across multiple pages and components. <div style="display: flex; flex-direction: column; height: 100%"> //inner html will vary based on c ...

Error encountered: The combination of NextJS and Mongoose is causing a TypeError where it is unable to read properties of undefined, specifically when trying

Versions: Next.js 14.1 React 18 I am currently developing a profile section where users can update their profile information such as username, name, and profile photo. To achieve this, I have implemented a component that contains a form (using shadcn) to ...

Property of object (TS) cannot be accessed

My question relates to a piece of TypeScript code Here is the code snippet: export function load_form_actions() { $('#step_2_form').on('ajax:before', function(data) { $('#step_2_submit_btn').hide(); $(&ap ...

Access to Angular 7 granted through Gmail authentication

I am currently attempting to authorize Gmail in Angular 7 using Angular5-social-login. While it is working for me, I need the function to run on page load. I have tried calling it in ngOnInit and ngAfterViewInit but encountered the following error: Un ...