I have a select with options. I would like to initialize the select value regarding to the user logged ng-init="own = credentials.user_id"
.
It works when the user_id
is equals to the value in the select
.
But when it's not equals, the value selected is "?"
. So there is no error whereas it should be.
I would like to not selected this "?"
and invalidate the form.
Do you have a solution ?
<div ng-class="{ 'error-select': myForm.lead.$error.required == true }"><span>Leader</span></div>
<select ng-model="lead" name="lead" ng-options="leader.user_id as leader.user_display_name for leader in leaders" ng-init="lead = credentials.user_id" required></select>
<div ng-class="{ 'error-select': myForm.own.$error.required == true }"><span>Leader</span></div>
<select ng-model="own" name="own" ng-options="own.user_id as own.user_display_name for own in owns" ng-init="own = credentials.user_id" required></select>
OUTPUT : user_id = 4
<select t ng-model="lead" name="lead" ng-options="leader.user_id as leader.user_display_name for leader in leaders" ng-init="lead = credentials.user_id" required="" class="ng-pristine ng-valid ng-valid-required">
<option value="0">Alexandre</option>
<option value="1">Antoine</option>
<option value="2">Zaaza</option>
<option value="3">toro</option>
<option value="4"selected="selected">Steffi</option>
</select>
<select t ng-model="own" name="own" ng-options="own.user_id as leader.user_display_name for own in owns" ng-init="own = credentials.user_id" required="" class="ng-pristine ng-valid ng-valid-required">
<option value="?" selected="selected"></option>
<option value="1">Alexandre</option>
<option value="2">Steffi</option>
</select>
This requirement is not so trivial and there could be several approaches to it. (I am not really sure the chosen one is the best.)
TL;DR
Here is the working demo.
What's going on ?
First things first: we need to understand what is actually happening.
A control's validity state (
$valid
/$invalid
) depends on the$modelValue
or$viewValue
. The key-point here is that is does not depend on the elements actualvalue
property.When you try to set the
$modelValue
to something that is not in theusers
array (e.g. 3), i.e. that there is no valid<option>
element available, then Angular will set$modelValue
and$viewValue
to 3, but the<select>
'svalue
will be either?
(if you haven't added an empty<option>
element) or whatever the value of the explicitely added empty<option>
.But since tha validation is not based on the elements
value
everything seems$valid
from arequired
standpoint.A solution
One solution is to create a custom directive that has access to the elements
ngModelController
and "hooks" itself to the$render()
function.This directive will check if the element's
value
is?
(which indicates an invalid$modelValue
) and if so, set the$modelValue
/$viewValue
to something actually empty, which will correctly update the validity of the control (i.e. an invalid$modelValue
will trigger our directive's handler to reset that to something empty and therequired
constaint won't be fulfilled).Here is the code:
See, also, this short demo.
A few points to note regarding the above implementation:
I chose to name my directive
select
so it will be applied to all select elements (alongside the native Angularselect
directive - yes that's possible). If you prefer to apply it to specific controls only, then rename it, restrict it to attributes (restrict: 'A'
) and add it as an attribute to your elements.Due (or thanks) to
require: '?ngModel'
, the control will be ignored if it is not bound to anngModel
.Since our directive augments the
ngModelController.$render()
method, which is defined by theselect
directive (executing at priority 0), we need to force our directive's link function to be executed after theselect
directive. Thus, it needs a higher priority, because "post-link functions are run in reverse [priority] order.".