When form.setValues() is called, asynchronous validation is triggered repeatedly

In my Angular 5 application, I am utilizing the reactive forms approach.

Within an Angular Material dialog, I have a form that is used for both data entry and editing. The constructor in my code looks like this:

constructor(public formBuilder: FormBuilder,
    public documentService: DocumentService, 
    @Inject(MAT_DIALOG_DATA) public data: any) {
    this.createForm();
    if (this.data.edit) {
        this.setValues();
    }
    this.setTitles();
}

The createForm function creates a reactive form with async validation:

createForm() {
    this.documentForm = this.formBuilder.group({
        ...
        documentNumber: new FormControl('',
                {
                    updateOn: 'blur',
                    validators: [Validators.required],
                    asyncValidators: [this.checkDocumentNumber.bind(this)]
                }),

        ...
    });
}

If the dialog is in 'edit' mode, the setValues function is called to populate the form fields that need editing:

setValue() {
    this.form.patchData({
        ...
        documentNumber: this.data.document.documentNumber
        ...
    });
}

The setTitles function sets the title of the dialog.

The checkDocumentNumber method validates a document number using an API call:

checkDocumentNumber(control: AbstractControl): Observable<ValidationErrors | null> {
    const formValue = this.form.value;
    return this.documentService
        .checkDocumentNumber(new Document(this.data.edit ? this.data.document.id : 0,
            form.documentNumber)).pipe(map((response: boolean) => {
            return response ? { inUse: true } : null;
        }));
}

The API call made is:

checkDocumentNumber(doc: Document) {
    return this.http.post(`/Documents/Inbox/CheckDocumentNumber`, doc);
}

To open the form dialog in 'edit' mode, you can use the following code:

this.dialogService.open(DocumentDialogComponent,
    {
        data: {
            edit: true,
            document: this.document
        }
    });

An issue arises when I attempt to edit document data within the dialog. Multiple unnecessary API calls are being triggered, resulting in delays. How can I prevent Angular from making these redundant API calls? I believed that the addition of the updateOn flag in Angular 5 would address this, but it seems to persist.

For reference, here is a snapshot showing the API calls being initiated:

https://i.sstatic.net/MSeXG.png

Answer №1

If you want to minimize the number of triggers, consider utilizing the debouncePromise method. This could potentially be linked to the view being re-rendered.

asyncValidators: [debouncePromise(this.checkDocumentNumber.bind(this))]

Answer №2

Angular initiates the request whenever a value changes. The documentation recommends using async validators only after passing synchronous ones to prevent costly async validation processes like an HTTP request.

Here's my interpretation of the situation:

  • updateOn: 'blur' is intended for user interactions and does not apply when programmatically changing the value.

  • Upon form instantiation, the validator is triggered, prompting a request.

  • When you call patchData() within setValue(), the validator runs again.

  • I suspect that Angular uses switchMap internally for the validation Observable, explaining cancellations upon value changes.

As for the 9 requests issue, I would need to see the complete code to provide a precise analysis (@EstusFlask mentioned providing a Minimal, Complete, and Verifiable example at ).

Suggestions for improvement:

  • Incorporate some synchronous validators like Validators.required to prevent requests for empty values, including the initial ''.

  • Rather than patching the default value separately after creating the form, calculate the default during creation.
    While unnecessary with required in cases where the default is empty, it improves readability in other scenarios.

    const defaultDocumentNumber = this.data.edit ? this.data.document.documentNumber : '';
    ...
    documentNumber: new FormControl(defaultDocumentNumber, ... 
    
  • If other form controls trigger validations leading to numerous calls, consider utilizing the optional parameters emitEvent and onlySelf in FormControl.patchValue() to control validation triggers more effectively.
    A reproducible example is necessary for accurate guidance. Refer to the docs for more information.

Answer №3

We encountered a situation where the problem stemmed from the input being deleted from the DOM. When hiding a field, it is important to not only remove it from the view but also from the reactive form.

Our theory is that Angular keeps trying to validate asynchronously when it cannot locate the form input.

Answer №4

According to the explanation provided in this particular response, excessive rendering may lead to multiple triggers during asynchronous validation. I encountered a similar issue, and applying debounceTime(1) proved to be an effective solution for me.

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

Transform OKTA Observable into a practical string variable

I'm currently in the process of developing a service in Angular 12 that retrieves a "User" object, with OKTA being used for authentication. My goal is to streamline the process. I can easily obtain the family name as an Observable using the following ...

Combining objects with arrays to create a single unified data structure

I am trying to merge two array objects to achieve a specific structure, similar to the example below. "feedBackList" : [ { "questionNo" : 1, "scoring" : "5" }, { ...

The provided argument, which is of type 'RefObject<HTMLDivElement>', cannot be assigned to the parameter of type 'IDivPosition'

Currently, I am implementing Typescript with React. To organize my code, I've created a separate file for my custom function called DivPosition.tsx. In this setup, I am utilizing useRef to pass the reference of the div element to my function. However ...

The JokesService (?) has encountered dependency resolution issues that Nest is unable to resolve

Currently delving into the world of NestJS and feeling a bit perplexed about the workings of "modules". In my project, I have two modules namely JokesModule and ChuckNorrisApiModule. My goal is to utilize the service provided by ChukNorrisService within th ...

Ways to Access HTTP Request Headers in Angular 6 upon Page Load

Is it possible to retrieve request header information in Angular 6/7 upon application initialization? I specifically require access to header values for security and access management purposes, as these values are set in the headers during the usage of th ...

How can we encapsulate the dx-data-grid along with its tools within a separate component and effectively manage it as a controller component?

We've been working on an angular application using devexpress.com. I'm trying to create a 'my-grid' controller with dx-data-grid, and I want to integrate dx-data-grid tools into it. However, I encountered an issue while attempting this. ...

Angular 2 experiencing issues with the authorization header

Hello there! I am currently working with the Ionic 2 framework alongside Angular, and I'm facing an issue while trying to make an HTTP request with the authorization header. It seems like the header is not being sent properly. Can someone help me iden ...

Tips for creating type-safe expressions for @Input() in Angular 2 and above?

What's the best way to create a function using @Input() in an Angular component? For instance, when defining a method that should return a boolean value: @Input callback: //(only allow methods with boolean return value) @Input callback: Function // ...

Running my Angular Single Page Application on a self-hosted ServiceStack service

Currently, I am utilizing ServiceStack to construct a small self-hosted RESTApi service with a NoSQL database and the setup is working perfectly fine (without using .Net Core). My next step involves creating some maintenance screens using Angular. Howeve ...

The date format being sent by Angular to Java is incorrect, resulting in the inability to create an object in the

In my coupon system, I am experiencing an issue with the date format. The Java coupon bean has a date.sql startDate and endDate, while the Angular coupon model includes startDate:Date and endDate:Date in its constructor. However, when I display the dates o ...

Differences Between Angular Module and Library

Exciting news - Angular has recently launched version 6 with a new CLI feature that allows you to generate libraries, which they are calling a "highly anticipated feature". From a business standpoint, I am left pondering the following questions: What is ...

Achieving a successful Reset Password functionality with ASP.NET Core and Angular

I've been working on setting up password recovery for users who forget their passwords and need to reset them. One issue I'm facing is figuring out how to properly generate the recovery link that is sent to the user via email. Should the link le ...

Accessing route parameters in Angular directly from the templateFinding route parameters in

There are times when my routes have multiple parameters like: /checklists/:type/:view/:filter I want to generate links in the template in this manner: <a routerLink="['/checklists',':type',':view',':filter']"> ...

Having trouble with VSCode/tsconfig path configurations, as the files are being fetched but still receiving a "Module not found" error in the editor

Since I began working on this project, I've been encountering a peculiar issue. When importing modules and files in my Angular components/classes using import, I face an error in VSCode when the paths use the base path symbol @. Strangely enough, desp ...

Designing a visual showcase with interactive tab links for image selection

I have been working on developing an Angular component that simulates a tab gallery functionality, inspired by this example. Below is my HTML structure: <div class="gallery-container"> <div class="display-container"> ...

The custom component in ngx-formly remains unchanged after updating the model

I am utilizing custom component fields in my project. Initially, everything works smoothly until I attempt to replace the model with a different one. Unfortunately, the component for each field does not get updated with the new value. No events seem to ...

Accessing the 8100 ionic application from any port or device other than the original one is not possible

I have successfully developed an Ionic application that runs smoothly on the browser using port 8100. However, I am encountering issues with logging in from simulator or any other port. I have implemented httpClient to fetch headers. Can someone please pro ...

Enhancing validation in Express with custom Typescript types for validation in Express Validator

I encountered an error while using the custom method of the express validator Issue: Argument of type '(userDoc: User | null) => Promise<never> | undefined' is not assignable to parameter of type '(value: User | null) => Promise ...

The received HTTP response error status is showing as 0, which does not match the actual status

I am currently facing an issue in my Angular 4 code while handling errors that occur during a service call. My goal is to take specific actions based on the error code returned, whether it be 403, 200, or any other code. When I subscribe to the Observable ...

Angular 9 and Bootstrap 4 combined in a row featuring up to 2 items maximum

Here's the HTML I'm working with: <div class="row"> <div formArrayName="addresses" *ngFor="let address of addressesFormArr.controls; let i = index" [formGroupName]="i"> <div *ngIf="i % 2 === 0" class="col-auto"> ...