Angular reactive forms - does pristine reset when the user reverts the UI changes to original values?
Asked Answered
B

2

7

I want to enable the Submit button in the form only when the form input is changed.

The Submit button should be disabled when the form control values are not changed.

I tried to use the FormGroup.pristine flag for the enable / disable of the Submit button.

It works fine for enabling the button.

However, it does not get reset to true when the value in the UI is changed back to its original value.

The component code:

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

@Component({
  selector: 'app-registration-form',
  templateUrl: './registration-form.component.html',
  styleUrls: ['./registration-form.component.scss']
})
export class RegistrationFormComponent {
  public registrationForm;
  public formValues = {
      gender: 1,
    };

  constructor(private formBuilder: FormBuilder) {
    this.registrationForm = formBuilder.group(this.formValues);
  }

  onSubmit(formData) {
    console.log('Your form is submitted', formData);
    this.registrationForm.reset(this.formValues);
  }
}
<form class="registration-form" [formGroup]="registrationForm" (ngSubmit)="onSubmit(registrationForm.value)">
  <div>
    <label for="gender">Gender</label>
    <select id="gender" formControlName="gender">
      <option value=1>female</option>
      <option value=2>male</option>
      <option value=3>do not specify</option>
    </select>
  </div>
  <input type="submit" [disabled]="registrationForm.pristine">
</form>

By default, the option "female" is selected in the select box.

When the user changes it to "male", for example, the Submit button is enabled.

Now when the user selects "female" again, the Submit button does not become disabled.

The user has to click the Submit button in order to get back the pristine status and get the button disabled.

How to reset to pristine status when the user changes back the select box value to default, without clicking the Submit button?

Angular version: 8.2.14.

Update

Sadly angular does not seem to change form status to pristine, when the user changes UI to default values.

So we have to write code to do the data comparison and mark the form to pristine status.

Bonnett answered 19/8, 2020 at 13:45 Comment(1)
You can subscribe to ValueChanges this.registrationForm.valueChanges.subscribe(x => {})Deuno
R
10

You can use markAsPristine method to set pristine status true, when the data changes back to defaultValue like this:

ngOnInit() {
    const defaultValue = this.registrationForm.value;
    this.registrationForm.valueChanges
      .pipe(debounceTime(200))
      .subscribe(value => {
        if (JSON.stringify(defaultValue) == JSON.stringify(value)) {
          this.registrationForm.markAsPristine();
        }
      });
  }
Rectum answered 19/8, 2020 at 14:16 Comment(5)
Hi Chellappan, thank you for your answer. Similar to Minal's answer, your answer makes it clear that angular does not take care of it by default, and we need to take care of it. Typically a form would have more than one value. So we have to write an object comparison logic or use a library like lodash as Minal's answer. This is disappointing from the angular side unfortunately.Bonnett
That's true, Since FormGroup provide valueChanges API as Observable, If you have lot text input, we can use rxjs debounce operators to reduce number markAsPristine method call.Cypripedium
Can you please change your code example to subscribe to FormGroup instead of only gender control? I believe it is more suitable approach to my question.Bonnett
I have updated can you check now: instead of using JSON.strinfy you can use loadash or some other way to check object comparision Example:stackblitz.com/edit/angular-ivy-1itbpo?file=src/app/…Cypripedium
Thank you Chellappan, I could take the lodash comparison idea from Minal's answer instead of JSON.stringify. But overall since you suggested a more angular approach with valueChanges observable and markAsPristine I will mark your answer as accepted.Bonnett
A
2

You can make one method that returns true or false for disabling the submit button if nothing is changed.

Assuming you have some object that is used for storing the inputs of the form.

Refer the below code for the function:

oldObj = _.cloneDeep(this.obj)
dataChanged(){
 return !_.isEqual(this.oldObj, this.obj)
}

and in the html add the below line

<input type="submit" [disabled]="!hasChanged()">
Avellaneda answered 19/8, 2020 at 13:59 Comment(3)
thank you for your answer. I was expecting angular to provide this functionality by default, so that we do not have to write this comparison logic. So this kind of code I am trying to avoid. Sadly, once the user changes input, angular sets the form status to dirty and does not change it even if the user reverts his UI change.Bonnett
Yeah there is no other way directly provided by angular to handle this.Avellaneda
Hi Minal, I will go with Chellappan's answer, but I like your lodash comparison idea, so will upvote your answer.Bonnett

© 2022 - 2024 — McMap. All rights reserved.