angular2 formcontrol stays dirty even if set to original value
Asked Answered
S

2

13

When I change a value in an input field, the corresponding form-control is set to dirty. When I revert my change (by typing in the input field) the form-control stays dirty. Is this intended, is this a bug or do I do something wrong?

Sermonize answered 7/12, 2016 at 16:14 Comment(3)
You already touched the input, then, It's dity! You can force Untouched by coding if the input is empty for example!Malave
You should read the AbstractControl documentation which lists out what the states are and how they are set: angular.io/docs/ts/latest/api/forms/index/… Generally, searching the documentation first before asking SO is a good idea.Abra
It is not clear that if the user changes a value and then changes it back to it's initial state, the value is still changed. The meaning of the word dirty is different. When someone makes something dirty and cleans it afterwards, it is not dirty any more!Sermonize
H
14

Well, yes it's intended to work that way since:

A control is dirty if the user has changed the value in the UI. (docs entry)

..and not if the value is different from the starting value.


In case you want to revert the dirty state you could use the markAsPristine() (docs entry) on your AbstractControl. (eg trigger it by click on a button or when subscribing to the valueChanges observable of the AbstractControl and compare the new value to a previously stored one...)

Herzel answered 7/12, 2016 at 16:37 Comment(4)
but that's not the meaning of the word dirtySermonize
Well eg: you've got a (clean and crystal clear) glass of water in front of you. You take the glass drink some the water and you refill it to its original ml count.. the ml of water in your glass might still be the same but it got your fingerprints on its.. hence it's dirty now.. ..so we've got our dishwasher called markAsPristine() for thatHerzel
Yes, user3725805 is correct -- that is touched. Otherwise, why is dirty even there if after we rinse our glass and refill it our dishwasher thinks there's still backwash??? I'm sorry, this makes absolute nonsense. So the Angular team said, "Hey, let's come up with a totally hideous definition of what 'dirty' means so that nobody can tell if the form looks exactly like it did before any input". How can we tell if the form looks exactly as it did before input, then???????????????????Zobkiw
touched indicates that a user visited the control, regardless of whether the value has changed. This is useful as a separate event from dirty since we may want to know when the user has blurred (touched) an input, even if the value is the same (e.g. to show an invalid state only after they've visited the input). If you want to know whether or not a control has been changed, store the original value, listen for changes on the input with valueChanges, and compare the new value with the original.Selangor
W
0

For a slightly different requirement, if we want to check if the input went back to empty (user deleted entry) after being dirty to not display the error message for ex, we will also face the same issue with "dirty" behavior.
In this case, as additional response to this post, I recommend creating a custom directive and apply it to all the inputs of the forms.
If input is empty and user click away after being dirty, we can apply the already mentioned markAsPristine() or markAsUntouched()

@Directive({
  selector: '[noErrorOnEmpty]'
})
export class NoErrorOnEmptyDirective {
  constructor(private control: NgControl) {}

  @HostListener('blur')
  onBlur() {
    const control = this.control.control;
    if (control?.value === '') {
      control.markAsUntouched();
      control.markAsPristine();
    }
  }
}

Then apply it on each of your inputs

<input
formControlName="username"
noErrorOnEmpty

--
OR
Add just add a function in your component

noErrorOnEmpty() {
  Object.keys(this.userForm.controls).forEach(field => {
    const control = this.userForm.get(field);

    if (control?.value === '') {
      control.markAsUntouched();
      control.markAsPristine();
    }
});

}

Then apply it on each of your inputs

<input
formControlName="username"
(blur)="noErrorOnEmpty()"
Wiencke answered 15/8, 2024 at 8:40 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.