Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

ng-change's viewChangeListener firing before validity update #9564

Closed
tdakhla opened this issue Oct 10, 2014 · 5 comments
Closed

ng-change's viewChangeListener firing before validity update #9564

tdakhla opened this issue Oct 10, 2014 · 5 comments

Comments

@tdakhla
Copy link

tdakhla commented Oct 10, 2014

Before 1.3.0-rc.4, if I had a required, initially empty radio box, state was off a lot (http://jsfiddle.net/butyz12m/):

  • Given ng-click="change(parentForm)", the change fn sees parentForm.$invalid being true (incorrect) and the model value being undefined (incorrect).
  • Given ng-change="change(parentForm)", the change fn sees parentForm.$invalid being true (incorrect) and the model value being b (correct).

After 1.3.0-rc.4, the behavior is now a lot better, but still off slightly in the ng-change case (http://jsfiddle.net/tq321axv/):

  • Given ng-click="change(parentForm)", the change fn sees parentForm.$invalid being false (correct) and the model value being a (correct).
  • Given ng-change="change(parentForm)", the change fn sees parentForm.$invalid being true (incorrect) and the model value being b (correct).

From what I could debug/track down, ng-change is firing early because it's in the $viewChangeListeners queue, which occurs before $digest. I don't know what the appropriate way of delaying the change is, but I'd assume it should stay consistent with when ng-click and ngEvents fire.

I know this is probably under the category of "undefined behavior", but I just wanted to mention it cause I noticed things improving after 1.3.0-rc.4 yet there's still this minor discrepancy between ng-click and ng-change. IMO, things have improved a lot due to ng-model being increased in priority: 1064443#diff-c244afd8def7f268b16ee91a0341c4b2R2397.

@caitp
Copy link
Contributor

caitp commented Oct 10, 2014

I mean the thing is, the click event is just the browser telling us that a click happened, we don't really have a way to tell it to wait until a view change listener is fired (it would be expensive to implement a way to defer evaluating the passed expression until view change, if a view change was needed --- and even if we did, it wouldn't help other jQuery events).

I'm not sure there is much we can do about this, but I think it might be wise not to depend on validity state in an event listener unless you're very careful about it. What in particularly are you working on that you need to do this? Maybe there's a better way to take care of it.

@caitp
Copy link
Contributor

caitp commented Oct 10, 2014

Given what I've said above, and the fact that I have no idea how to triage this one, lets say we close it and you ask around for better solutions to what you're trying to do on #angularjs on irc.freenode.net, or else on stackoverflow.

Sorry to close the issue but, :(

@tdakhla
Copy link
Author

tdakhla commented Oct 10, 2014

I agree that deferred evaluation is not ideal, but as of 1.3.0-rc.4+ that's currently what's happening with all ngEvents such as ng-click. I'm just recommending that ng-change follow suit and stay consistent with all the other events, but I'm not sure what the correct delay mechanism is without going through the code a bit more.

The long-standing workaround I've used for both pre- and now post-1.3.0-rc.4 is to execute the code inside a $timeout of 0 and then read the parentForm, but after seeing the ngModel priority increase I didn't think it would be much more work to defer ng-change eval just a tad by hooking it somewhere later.

@caitp
Copy link
Contributor

caitp commented Oct 10, 2014

but as of 1.3.0-rc.4+ that's currently what's happening with all ngEvents such as ng-click.

It's not actually what's happening with ngEvents (with the exception of focus and blur events). What actually happens for other events is the expression gets evaluated as soon as we get the event.

@tdakhla
Copy link
Author

tdakhla commented Oct 13, 2014

Sorry about that - you're absolutely right. Only a few events actually end up getting delayed, and ones such as ng-mousedown, ng-mouseup, and ng-focus will get fired before ng-click. Doesn't seem like there's any guarantee as far as the form object or model value being in place before event handlers fire. Thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants