Form marked as dirty after updating form contents to their initial state

2,406 views
Skip to first unread message

Jeremy Whitlock

unread,
Feb 27, 2013, 1:44:01 AM2/27/13
to ang...@googlegroups.com
Hello all,
    Let's say I've got an ngClass that enables/disables buttons based on the form's state (dirty or pristine).  For the most part, this works great but I've noticed an anomaly where if I have a form, I change a field and then change its value back to its initial state but $dirty is still true and $pristine is false.  I realize that based on the verbiage in the documentation things appear to be working as designed but in the grand scheme of things, if the forms contents are back to its initial state shouldn't the $dirty be false and $pristine be true?  I did a bit of searching this group and on Google and the only thing I can find is issue 856 (https://github.com/angular/angular.js/issues/856) which is a nice addition to the FormController but it really doesn't solve the problem where the form is being marked as dirty when from a content/model change perspective, it's really in its initial state.

All this being said, does anyone else see this as a bug/issue?  Is this something that can be worked around using AngularJS?

Take care,

Jeremy

P.S. - I realize I could write a controller function that could give me a workaround/solution but I figured I'd bring this up here to see if it's worth putting into AngularJS.

Jeremy Whitlock

unread,
Feb 27, 2013, 12:04:02 PM2/27/13
to ang...@googlegroups.com
Looks like my attempts to work around this are failing.  Any time I try to store a pristine, or original state, of the model in my scope, I get two-way bindings so that any changes to the model results in changes to my original copy.  I'm still looking into this.

Peter Bacon Darwin

unread,
Feb 27, 2013, 12:15:48 PM2/27/13
to ang...@googlegroups.com
OK, so you have a couple of solutions.  One is to actually make a "copy" of the original - it is not enough to simply reference it - using angular.copy()
The other is to use the FormController.$setPristine() method.


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Jeremy Whitlock

unread,
Feb 27, 2013, 1:21:47 PM2/27/13
to ang...@googlegroups.com
Peter,
    Copying with angular.copy works but now that I can create a pristine copy of my object, but now I'm fighting with how Angular handles form validation and binding.  It seems if you have a required field and you remove all content, the field is removed completely from the object.  So if I have an object {name, description, content} and name is required but empty, I have an object like {description, content}.  Again, from a form perspective things are back in their original state (all inputs are empty) but my cloned model has {name, description, content} while my bound model has {description, content}.  So it seems that even attempting to work around the form.$dirty and form.$prisitine is proving quite painful.  As for calling the form.$setPristine(), I do realize I can do that via a "Revert" button or something but the idea is to have these buttons enable based on the user's input.

I'll keep thinking.

Take care,

Jeremy

Caleb Olin

unread,
May 15, 2013, 12:07:12 PM5/15/13
to ang...@googlegroups.com
Hey Jeremy, did you find a solution for this? I'm wrestling with the same problem.

Caleb

Caleb Olin

unread,
May 15, 2013, 1:03:35 PM5/15/13
to ang...@googlegroups.com
Here's a fiddle that illustrates the issue: http://jsfiddle.net/x3nXj/1/

Jeremy Whitlock

unread,
May 15, 2013, 1:06:33 PM5/15/13
to ang...@googlegroups.com
Caleb,
    Below is a link to a sample project I ported from Backbone.js to AngularJS:


If you look on line 66, you'll see where I comment about the issue and explain my approach.  I'm not saying it's the best approach but it worked for me.

Take care,

Jeremy

Caleb Olin

unread,
May 15, 2013, 4:09:59 PM5/15/13
to ang...@googlegroups.com
Thanks Jeremy, I see what you did and I have something similar in my app. The problem I'm trying to solve is that angular deletes the property from the object when you empty out a text input. When that happens you'll no longer have equality between the "master" object and the "active" object. It looks to me like your example is still susceptible to that. True?

Jeremy Whitlock

unread,
May 16, 2013, 10:23:28 AM5/16/13
to ang...@googlegroups.com
Caleb,
I'm not sure, it worked last I tried but I've not played with it in a while.

Take care,

Jeremy Whitlock <jcsco...@gmail.com>
Twitter: whitlockjc

You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/kcx0ZRP8yvw/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.

westd

unread,
May 19, 2013, 11:09:21 PM5/19/13
to ang...@googlegroups.com
I believe I've had the same issue you've mentioned. My objective was to disable a "save" button and prevent a network request, if the form corresponding to some model wasn't in fact changed from its initial value. Getting around it is fairly straightforward if you're willing to make changes to the ngModelController and FormController within Angular. You can also get around it by sort of conditionally monkey-patching those two controllers from the outside.

I actually posted about this a little while back (see: https://groups.google.com/forum/#!topic/angular/e88cLhrrgmM ). In that post, you can find a plunkr demo with sort of a working solution, albeit a hack. I basically just added a $revisionValue property to ngModel which tracks the last known persisted value of the model. The ngModelController also tracks a property published to a parent scope, which indicates when a new revision has been persisted and resets the $revisionValue to the latest persisted value. Then, whether a model is $dirty or $pristine depends on whether its current value matches its $revisionValue.

Lastly, to solve the problem of the "save" button -- i.e. disabling/enabling it based on the entire form being $pristine or not, I added a method "$isAllPristine" to Angular's FormController, which loops through each contained control, stops when it finds one which is $dirty, and finally returns true/false depending on what it finds. The save button can then watch the result of $isAllPristine on its parent FormController and be enabled/disabled accordingly.

-west
Reply all
Reply to author
Forward
0 new messages