1
votes

In Angular template driven form I want to validate input fields conditionally, based on which button was clicked. Then in the ts component file I check whether the form is valid i.e action can be executed or invalid i.e form data needs to be corrected. I use the form template reference variable to determine if form is valid or not <form #heroForm="ngForm">, then in the .ts file @ViewChild('heroForm') form:Ngform; When a button is clicked I set the condition whether the field is required or not and then evaluate whether the form is valid or not.

However, when I set the variable actionType = 'A' so that the input is required and then right after evaluate this.form.valid it tells me the form is valid even though it is not ( required input is missing data)

this.actionType = 'A';//this make the input field required
if(this.form.valid){ // should be false but it is true (although later it changes to false)
 //code that should be executed when form is valid
}

After I debugged the app I noticed that setting a variable with new value then running validation is done asynchronously, therefore this.form.valid is checked before previous operation is finished.

When I put the form checking code inside setTimeout it works but I am not sure this is the correct way to handle this case.

Is there any other way this should or can be solved?

I created a stackblitz sample to illustrate the problem https://stackblitz.com/edit/angular-g1nb9s

Watch the console output to see what is happening.

Expected behaviour:

  • I click actionA button
  • input field becomes required by setting actionType = 'A'
  • value of this.form.valid in ts file should be false ( because input is required and is empty)

Currently when I click actionA button and read immediately this.form.valid in component file, then the value is true

2
Not sure why you're not able to do that. I just checked your StackBlitz sample, it's working as expected for me. - SiddAjmera
I added description of what expected behavior is, check it out. Watch the console output to notice that the form.valid is true even though data is missing in a required field. - Antoni
No, it's not. The forms validity is set to false as soon as you click button a. Unless I'm extremely dumb and not noticing something obvious. - SiddAjmera
Thanks for your input. I simplified the stackblitz sample not to be confusing. Open up the console and press actionA button. - Antoni

2 Answers

0
votes

Changes actionType will not immediately be reflected in template. These changes will be seen in the template only after the next tick. You can use setTimeout as follows:

  public onClickA(){
    this.actionType = 'A';
    setTimeout(()=>{this.buttonClicked()},0)
  }

  public onClickB(){
    this.actionType = 'B';
    setTimeout(()=>{this.buttonClicked()},0)
  }
0
votes

You're using the required attribute with attribute binding syntax([required]="actionType === 'A'") which makes sense.

Since it's taking some time for Angular to detect these changes, you can explicitly tell Angular to do just that. This can be done by calling detectChanges on ChangeDetectorRef which you'll have to import from @angular/core.

Also, there's an issue with the type of heroForm that you've declared. @ViewChild('heroForm') form: Ngform; needs to be changed to @ViewChild('heroForm') form: NgForm; and NgForm needs to be imported from @angular/forms:

import { Component, ViewChild, ChangeDetectorRef } from '@angular/core';
import { NgForm } from '@angular/forms';

...
@ViewChild('heroForm') form: NgForm;
...
constructor(private cdRef: ChangeDetectorRef) {}
...
public onClickA() {
  this.actionType = 'A';
  this.cdRef.detectChanges();
  console.log("Value of actionType->" + this.actionType);
  console.log("Value of form.valid->" + this.form.valid);
}

Here's an Updated StackBlitz for your reference.