I have been doing Angular.JS in production projects for months, that it did surprise me recently how I haven’t used drop-downs in it. Well, I mean how I haven’t used them enough to get into several problems I had in my current project, and other friends at the same office had in their project as well.
To save you the pain I went through, I’ll list some problems and solutions here, and then give you a video that shows going through all of them ans the thought process that led to the solutions.
someObject in the model has the same properties and values as
someObject in the
objectList, it will still not be selected.
It’ll only be selected if
someObject was actually one of the objects in
objectList or whatever. Otherwise, Angular.JS will insert an empty
option tag with no value or text and select that.
An un-documented (AFAIK) feature in
ng-options is that you can use some bits from the
ng-repeat directive with it, like
track by. This allows us to choose some property as the comparison key.
key property is a simple type, like
Invalid Value Sent On Server-Side Submit
When Angular.JS writes the
<option> tags from an
ng-options directive pointing to an array, the
value of the
option is always the index of the element it maps to in the array. This is not important if you process the selection on client side because you only deal with the result of
ng-model anyway, you can use this later to create an AJAX request or whatever.
However, if you intend to submit the form using a normal server submission, and only use Angular.JS for say validation or managing complex form interaction (client-side tables containing sub-items with add/remove/sort for example), this may be a road blocker to using Angular.
By default Angular.JS uses the index of the array to track which object maps to which
Similar to the previous problem, use the
track by syntax. Angular.JS will use the
track by property value as the
value. Most of the time your tracked property is the key property you want to send to the server anyway, so, this should be good enough.
Simple Properties Scenario When Combined With Server-Side Submit
Let’s say you want something as simple as this:
track by syntax, like
track by gender.id.
However, if you do this, you’ll notice that the
select is no longer usable. No initial selection, and changing selection although updates the model, it does not show the new selected value.
track by syntax expects an object, with the property you use to track. It does not honor the key part used in the
key as text syntax (which in our example is
g.id as g.text), so, it wants the
ng-model to point to an object with the tracked property, it cannot be the key itself directly.
I didn’t call this a solution, because it’s pretty much a hack.
We created a new property (which I liked to prefix with
_ to show it doesn’t normally belong to the model object), initialized it to a new object that contains only our key property
id set to the original simple value
genderId, and then used that as the model (as in
We created and assigned the property in
ng-init, then synchronized the changes to the simple property via
ng-change. This allows the code everywhere else in the application (like the controller, or other parts of the markup) to only interact with the property we want (
genderId in this example), without knowing about our hack. This makes things a bit cleaner, although it still remains a hack rather than a solution.
You can view an example of using this hack here.
Adding extra selection items to the dropdown
One thing you notice if you are affected by the “initial selection” problem, is that the empty
<option> tag that Angular.JS adds when it can’t match the
ng-model to the array from
ng-options disappears when the use changes their selection. We have gone through how to avoid showing the empty
option by mistake already.
But if you do want to have that option, it’s easy, just, um, add it!
If you are using Angular 1.4+, check the much smaller 2nd part of this article, about how to use
Using track by correctly with Angular 1.4 select ng-options – Why can’t I select this option?
If you want to dig these problems really deep and see what they look like in action, and what was the thought process for solving them like and in some cases other possible solutions, I have put all this in a (rather long) video here: