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 arrow function in Jest is missing a name property

Currently, my setup includes: node.js: 9.8.0 Jest: 23.4.2 ts-jest: 23.1.3 typescript: 2.9.2 While attempting the following in my *.test.ts files: const foo = () => 'bar'; console.log(foo.name); // '' foo contains the name pro ...

TypeScript error: Unable to locate namespace 'ng'

I am attempting to utilize a tsconfig.json file in order to avoid having ///

Issue encountered during the upgrade to Angular version 12: The specified root path is undefined and does not correspond to any file in the program

During the process of upgrading my Angular 11 app to version 12, I encountered an error after running ng update @angular/core@12 @angular/cli@12 and then executing yarn start. The error that appeared can be found here: [Error After Run Angular in version 1 ...

Is there a way to apply a css class to all nested elements in Angular 6 using Ngx Bootstrap?

I've defined a CSS class as follows: .panel-mobile-navs > ul > li { width:100% } Within the HTML, I am utilizing Ngx-bootstrap for a series of tabs like this: <tabset class="panel-mobile-navs" > ... </tabset> My intention is to ...

What is the process of creating an asynchronous function that will resolve a promise when the readline on('close') event is triggered within it in Typescript?

Here's a code snippet I'm working with: private readFile() { var innerPackageMap = new Map<string, DescriptorModel>(); // Start reading file. let rl = readline.createInterface({ input: fs.createReadStream(MY_INPUT_FILE ...

Uploading images to an S3 bucket using Angular4 and saving the response.Location in a global variable for easy access in other functions or methods

Hello, I am currently working on uploading an image to an Amazon S3 server using Angular 4. My goal is to retrieve the response.Location, which is returned from S3 as a URL, and save it to a global variable for easy access. However, I am facing some challe ...

Angular 4 HTTP Requests Failing to Retrieve JSON Data

I am currently working with the following method in my Typescript: allPowerPlants(onlyActive: boolean = false, page: number = 1): PowerPlant[] { const params: string = [ `onlyActive=${onlyActive}`, `page=${page}` ].join('&&apo ...

When using Angular9 with PrimeNG fullcalendar, it may encounter issues such as errors stating "Cannot find namespace 'FullCalendarVDom'." and "Please import the top-level fullcalendar lib"

Using primeng p-fullcalendar in my angular application. Encountering an error in the command-line: 'Cannot find namespace 'FullCalendarVDom' Also seeing this error in the browser: 'Please import the top-level fullcalendar lib before a ...

Angular 4 project encountered a running error with the following issue displayed

While developing an Angular 4 app in Visual Studio within the same solution as the backend, everything was running fine. However, after adding some services and installing the Moment package, I encountered the following error: I attempted to reinstall pa ...

"The latest version of Angular, version 15, experiencing issues with javascript loading

Currently, I am diving into the world of Angular and encountering a puzzling dilemma. Surprisingly, my application performs flawlessly on various browsers such as Chrome, Firefox, Brave, Opera, and even on mobile versions except for Safari. Both the deskto ...

Troubleshooting d3js Type Errors in Angular (Updated Version)

Encountering numerous type errors with d3js when integrating it into Angular (typescript). svg.call(d3.zoom().on('zoom', () => { g.attr('transform', d3.events.transform); })); Error thrown: S2345: Argument of type 'Zo ...

Is there a way to utilize an AXIOS GET response from one component in a different component?

I'm having trouble getting my answer from App.tsx, as I keep getting an error saying data.map is not a function. Can anyone offer some assistance? App.tsx import React, {useState} from 'react'; import axios from "axios"; import {g ...

Learn the dynamic binding method for <a href> templates in Angular 2!

Kindly review the code snippet provided below: Component.ts getReply():string{ if(condition){ return "The link is: <a href = 'https://www.google.com'>Google</a>"; } } In my front end, I am using [innerHtml] to bind ...

Issue with debugging Azure Functions TypeScript using f5 functionality is unresolved

I am encountering issues running my Azure TypeScript function locally in VS code. I am receiving the errors shown in the following image. Can someone please assist me with this? https://i.stack.imgur.com/s3xxG.png ...

Syncfusion Angular TreeGrid Hierarchy connectors and lines for improved data visualization

Is it possible to display guiding lines or connectors that represent the hierarchy of data in a Tree Grid? You can see an example with blue lines in the image below: ...

How is it possible that the type-checker is not flagging this code?

Do you find it acceptable that this code passes type-checking? function endlessLoop(): never { while (true) { } } let y = endlessLoop(); Why does y exist and fall under the never type category? ...

Retrieve the additional navigation information using Angular's `getCurrentNavigation()

I need to pass data along with the route from one component to another and retrieve it in the other component's constructor: Passing data: this.router.navigate(['/coaches/list'], { state: { updateMessage: this.processMessage }, ...

A step-by-step guide to activating multi-selection in the Primary SideBar of Visual Studio Code using your custom extension

Currently, I'm in the process of developing an extension for Visual Studio Code where I've added a new activityBar containing treeViews that showcase information pulled from a JSON file. My goal is to enable users to multi-select certain displaye ...

Change the API endpoint for webpack in production

In my Angular 4 project, I am utilizing webpack to manage the API url. However, for production, I need to specify a different API url. Can anyone guide me on where exactly I should input the new url in my jhipster project? Source: webpack.prod.js : ...

Angular asynchronous operations are failing to complete within the specified time frame

Observations suggest that Angular's async from @angular/core/testing is not properly resolving timeouts in tests when a beforeEach contains async as well. Sadly, the bug cannot be replicated on Plunkr or JSFiddle platforms. To reproduce this issue ea ...