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

Bug when using ngModel, $asyncValidators and SELECT elements. #8929

Closed

Description

@duncangrist

Tested and reproduced with version: 1.3.0-rc.0

If you use the relatively new $asyncValidators feature with SELECT elements bound to an ngModel the SELECT options become unselectable.

Please see the following plunk:
http://plnkr.co/edit/wlBKH2

This seems to be because $asyncValidators set the $modelValue to undefined while the async validators are running, but never set it back again to the actual value once all the async validators pass.

Activity

  1. gonzaloruizdevilla commented on Sep 4, 2014

    @gonzaloruizdevilla
    Contributor

    either PR #8861 or PR #8892 will solve this

  2. shahata commented on Sep 4, 2014

    @shahata
    Contributor

    No, I don't think so. This is is something else. This happens because select invokes render() right after $setViewValue() which sets an empty item as selected (since $modelValue is undefined). It can be easily solved by invoking ctrl.$render() when the async validator resolves, but I'm not sure if this is the best way to solve it.

    @petebacondarwin WDYT? (this is somewhat remotely related to cdc7db3f)

  3. petebacondarwin commented on Sep 4, 2014

    @petebacondarwin
    Contributor

    @shahata - without looking deeply into this, calling render() when the validator resolves (i.e. we are no longer pending) may work but perhaps we could go the other way and not call render() directly after $setViewValue() if we are in a $pending state?

  4. gonzaloruizdevilla commented on Sep 4, 2014

    @gonzaloruizdevilla
    Contributor

    I'm not sure this is the way to go, and it is not resolving the issue in all the cases. When you change a value in the select, the async validators are triggered three times instead of only once.

    UPDATE: in the plnkr, the changes in the select triggers its own async validation, then it triggers input async validation and then the select async validation is triggered a second time. Actually, I find it very difficult to determine what the expected behavior should be when both the input and the select have async validations on the same model value.

    http://plnkr.co/edit/EDuXlZopgARZ93kYSvGy?p=preview
    (this plnkr is a fork of @shahata 's )

  5. shahata commented on Sep 4, 2014

    @shahata
    Contributor

    @petebacondarwin hmm, but if render() isn't called then I guess there would be some bad consequences. After all, it's invoked there for a reason... From what I see, the reason render() is invoked there is in order to add/remove the "?" option when it becomes selected/unselected.

    Truth is I'm a bit confused by this render() function. Why does it have to use $modelValue and not $viewValue? I think just changing everything to $viewValue will solve this issue and will not break anything, but there is a good chance I'm missing something... I'm sending a PR to test this.

  6. duncangrist commented on Sep 4, 2014

    @duncangrist
    Author

    Glad this seems to be getting traction - when/if you do get a satisfactory fix, be sure to double check that selecting 0 (zero) works as when I quickly hacked my angular copy to fix this issue, I found that another bug stopped the selection of zero.
    I narrowed that bug down to NgModelController.$$setPending, resolve function - where it calls var value = ctrl.$viewValue || ''; and then uses that subsequent value when calling ctrl.$$updateValidModelValue(value);. This behaviour is causing 0 to be converted to an empty string which is then stored against the model.

    Let me know if there's anything else I can do.

  7. shahata commented on Sep 4, 2014

    @shahata
    Contributor

    @maximumduncan you can play around with this to see if your issue is resolved: http://plnkr.co/edit/3CDLMe?p=preview
    regarding the "0 becomes empty string thing", you'd better open a different issue for that, but the easy workaround is to use a string array instead of number array: ['0','1','2',...]

  8. duncangrist commented on Sep 5, 2014

    @duncangrist
    Author

    @shahata - yes, that does seem to resolve the original bug thanks.

    However, I disagree on the viability of your workaround for the "0 becomes empty string thing" because normally angular has no trouble when using zeros in selects. In your Plunk, if you remove the async-validate attribute from the select, and convert the strings back to ints, you'll see that zero behaves just like all the other numbers. It appears that it's specifically being broken by the $asyncValidators feature.

  9. shahata commented on Sep 5, 2014

    @shahata
    Contributor

    Yes, I agree that this should be reported as a different issue. The workaround is just that - a way to work around the issue.

  10. duncangrist commented on Sep 5, 2014

    @duncangrist
    Author

    Fair enough - I was going to raise it as an issue, but I hesitated because it's not actually a reproducible issue until this Issue's bug is resolved. What would you suggest is the correct play here?

  11. added this to the 1.3.0-rc.2 milestone on Sep 10, 2014
  12. 12 remaining items

  13. added a commit that references this issue on Oct 7, 2014
    e57c2af
  14. duncangrist commented on Oct 10, 2014

    @duncangrist
    Author

    I've confirmed that both issues reported in here are fixed my end when using 1.3.0-rc.5. Thanks a lot guys :)

  15. jfarid27 commented on Apr 4, 2016

    @jfarid27

    I'd love to reopen this. I'm able to recreate ng-model breaking in Angular 1.4.8 when using async validators, this time using just input text elements. Again the issue is when asyncValidators are added, changes to ng-model aren't ran when the viewValue changes.

    Version: 1.4.8
    Example: https://jsfiddle.net/ks0khrbc/

  16. jfarid27 commented on Apr 4, 2016

    @jfarid27

    I also went further and added asyncValidators by creating a new directive that accesses a required ngModel controller, as suggested by a coworker since that's the exact example defined in the documentation for forms. It surprisingly still breaks ng-model actually.

    https://jsfiddle.net/3seaL8qu/

  17. petebacondarwin commented on Apr 4, 2016

    @petebacondarwin
    Contributor

    @jfarid27 - I don't understand your use case. In both examples you return a promise that is never resolved, so of course the value never becomes valid, and so the model is not updated.

  18. jfarid27 commented on Apr 4, 2016

    @jfarid27

    @petebacondarwin yeah it seems to be the case. It was a little unintuitive but I wanted an async validation that does not immediately make requests to resolve and exposes the deferred objects for a separate service to resolve. Maybe there's a case for this, but it seems like more work to implement and a bad idea.

  19. petebacondarwin commented on Apr 4, 2016

    @petebacondarwin
    Contributor

    You should be able to do this. You can create a service that does the work and returns a promise to the async validator. When the promise is resolved by the service the validator will resolve too

  20. jfarid27 commented on Apr 5, 2016

    @jfarid27

    @petebacondarwin yes but I'd also love to see model view changes. I'm trying to do a "bulk" validation in one API call after a user fills out all their form elements then clicks a button. The moment I add an $asyncValidator, there are no longer any $modelView updates. I figured I would try to use the $asyncValidators, but it seems to serve only the specific purpose of validating model immediately and not allowing any updates to the $modelView until the promise is resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions