You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
Repository navigation
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
select with required and only 1 option fails to validate (and set ng-model) until change event is manually triggered #6288
I have a select element, using ng-option over an array of integers
<form name="form">
<select ng-model="bar.foo" ng-options="foo as foo|filter for foo in fooarray" required>
<option ng-if="fooarray.length > 1" value="" selected>Choose</option>
</select>
<input type="submit" ng-disabled="form.$invalid" />
</form>
When the fooarray has only 1 option, it should be chosen by default. Visually, it indeed is.
The DOM looks like this:
<select ng-model="bar.foo" ng-options="foo as foo|filter for foo in fooarray" class="ng-pristine form-control ng-invalid ng-invalid-required" required="">
<!-- ngIf: fooarray.length > 1 -->
<option value="0">filtered foo</option>
</select>
But:
the select is considered invalid, thus the submit is always disabled
the ng-model bar.foo is not set
furthemore clicking on the select and re-choosing the same option doesn't trigger an onchange event (presumably because there was indeed no change)
So the form is never actually valid.
Triggering a change event manually ($('select').trigger('change')) indeed sets the model and makes the form valid.
It would seem it's related to the conditional <option>, since when I remove it in the source, the select magically gets another (empty and default) option - but then the only option I wanted is no longer longer default, nor ..the only one. Which is IMHO a second bug.
I do care about the empty option so the second version doesn't work for me.
As for the first one... it's definitely much nicer than the hack I came up with (adding a directive that triggers change after a timeout), so thanks for that :).
However, I use the form for both create and edit, so adding something akin to if (mode == "new" && $scope.fooarray.length == 1) { $scope.bar.foo = $scope.fooarray[0]; } works, it still feels ..wrong, somehow.
Additionally, it has the problem that if the existing bar object (in edit mode) has the foo attribute set to something not in the array, (eg. bar.foo == 2), there's still no way for the user the select the 1.
But really, it's not that I can't work around that issue, that's fine ... what bugs me is that IMO ng-model on a select should always match the select's state, which doesn't happen here, so I think that part is a bug on angular's part. When creating the issue, I wasn't in the problem-solving state, I'd probably use stackoverflow for that, I was in bug-reporting state, if that makes sense :).
@himdel yes, I agree that this is a corner case, but I wasn't into the hack-proposing mode :-) The thing is that IMO selection should be driven from the model. If there is no proper model selection AngularJS would try to generate an empty option anyway (http://stackoverflow.com/questions/12654631/why-does-angularjs-include-an-empty-option-in-select/12654812#12654812), we are just killing it here with ngIf, hence the tricky scenario. But IMO it doesn't change the fact that it should be model driving the selection.
@pkozlowski-opensource I'm not sure about the model driving the selection, or rather, I think the user should be doing that, and AFAICT the user has no way of influencing the model directly. But yeah, let's not get philosophical :).
I do agree that the ngIf is the core problem here, and without it, there would be no problem, so I'll try to rethink that part. Probably I'll keep the "choose" option always there (remove the ngIf) and just preselect the first real option if none is set and the list has length 1.
Thanks for helping me through that.
Anyway, should I close the issue? I mean, on the one hand, I don't really have a problem anymore, but on the other, there is a (albeit rather specific) case where angular model doesn't match the state of the corresponding select..
submit the form : the general message "There are form errors" is displayed, but not the message near to the select, i.e. "Select a color !".
As @himdel wrote, if the select is used (performing the "change" event), then it works as expected.
@pkozlowski-opensource I understand the explanation given in your SO link, that Angular "don't want to decide model value on its own". But in my example, one difference with @himdel example is that the options are not generated with ng-options. I cannot find a way to link the first option to the model.
Do you think there is a solution to manage this case ?
@sebdavid Hi, your case can be solved trivially, by removing the empty optionand the required, angular will automagically add an empty option for you, and you don't really want required if you're OK with the user chosing the empty option. Unless I'm misunderstanding something :)
@himdel that's the point : I want the field to be required, and the select error message to be displayed.
But... after lunch it seems that the solution is so obvious : in my plnkr example, just remove the condition !userForm.color.$pristine in the select error span, and it works...
Finally, my problem was not really the same as yours, because I'm validating fields after the user submits the form. That's why I'm using $pristine on form elements, but for this case, it is useless on the select element.
The second version in original plunker works now (ngIf in the empty option is supported since 1.4.9 at least). The third version works as intended. If you want the first and only option to be auto-selected, you have to set it in the model. That's how angular works.
Activity
caitp commentedon Feb 17, 2014
Could you post a quick reproduction of this issue to a plnkr?
himdel commentedon Feb 17, 2014
Sure, here it is: http://plnkr.co/edit/ZecgGi9L88shcury3wd7?p=preview .
pkozlowski-opensource commentedon Feb 17, 2014
@himdel what about using data binding to select the single available option?
http://plnkr.co/edit/dB5AS7IP8KbIMSC0Fd2D?p=preview
A bit less code to write and seems to work as you would expect, no?
If you don't care about the empty option name, the HTML can be simplified a bit:
http://plnkr.co/edit/GEqmN4fMauTycNzjtuHP?p=preview
Does it work for you?
himdel commentedon Feb 17, 2014
@pkozlowski-opensource thanks...
I do care about the empty option so the second version doesn't work for me.
As for the first one... it's definitely much nicer than the hack I came up with (adding a directive that triggers change after a timeout), so thanks for that :).
However, I use the form for both create and edit, so adding something akin to
if (mode == "new" && $scope.fooarray.length == 1) { $scope.bar.foo = $scope.fooarray[0]; }works, it still feels ..wrong, somehow.Additionally, it has the problem that if the existing
barobject (in edit mode) has thefooattribute set to something not in the array, (eg.bar.foo == 2), there's still no way for the user the select the 1.But really, it's not that I can't work around that issue, that's fine ... what bugs me is that IMO
ng-modelon a select should always match the select's state, which doesn't happen here, so I think that part is a bug on angular's part. When creating the issue, I wasn't in the problem-solving state, I'd probably use stackoverflow for that, I was in bug-reporting state, if that makes sense :).But thanks anyway.
pkozlowski-opensource commentedon Feb 17, 2014
@himdel yes, I agree that this is a corner case, but I wasn't into the hack-proposing mode :-) The thing is that IMO selection should be driven from the model. If there is no proper model selection AngularJS would try to generate an empty option anyway (http://stackoverflow.com/questions/12654631/why-does-angularjs-include-an-empty-option-in-select/12654812#12654812), we are just killing it here with
ngIf, hence the tricky scenario. But IMO it doesn't change the fact that it should be model driving the selection.himdel commentedon Feb 17, 2014
@pkozlowski-opensource I'm not sure about the model driving the selection, or rather, I think the user should be doing that, and AFAICT the user has no way of influencing the model directly. But yeah, let's not get philosophical :).
I do agree that the
ngIfis the core problem here, and without it, there would be no problem, so I'll try to rethink that part. Probably I'll keep the "choose" option always there (remove thengIf) and just preselect the first real option if none is set and the list has length 1.Thanks for helping me through that.
Anyway, should I close the issue? I mean, on the one hand, I don't really have a problem anymore, but on the other, there is a (albeit rather specific) case where angular model doesn't match the state of the corresponding select..
sebdavid commentedon Feb 20, 2014
Hello,
Using v1.2.13, I was facing to a similar problem, when I read this thread.
Here is my example : http://plnkr.co/edit/DNLH2te8oxhVW3isN5E0?p=preview
And the steps to reproduce the "problem" :
As @himdel wrote, if the select is used (performing the "change" event), then it works as expected.
@pkozlowski-opensource I understand the explanation given in your SO link, that Angular "don't want to decide model value on its own". But in my example, one difference with @himdel example is that the options are not generated with ng-options. I cannot find a way to link the first option to the model.
Do you think there is a solution to manage this case ?
himdel commentedon Feb 20, 2014
@sebdavid Hi, your case can be solved trivially, by removing the empty
optionand therequired, angular will automagically add an emptyoptionfor you, and you don't really wantrequiredif you're OK with the user chosing the emptyoption. Unless I'm misunderstanding something :)sebdavid commentedon Feb 20, 2014
@himdel that's the point : I want the field to be required, and the select error message to be displayed.
But... after lunch it seems that the solution is so obvious : in my plnkr example, just remove the condition
!userForm.color.$pristinein the select error span, and it works...Finally, my problem was not really the same as yours, because I'm validating fields after the user submits the form. That's why I'm using $pristine on form elements, but for this case, it is useless on the select element.
vcardins commentedon May 7, 2015
Quite old thread but the solution posted here: #2365 (romario333) worked for me, in short:
Narretz commentedon Apr 11, 2016
The second version in original plunker works now (ngIf in the empty option is supported since 1.4.9 at least). The third version works as intended. If you want the first and only option to be auto-selected, you have to set it in the model. That's how angular works.
vaske commentedon Jan 13, 2018
Is there any way to remove red line in first example where it's required select and have default value which have value="" ?