AngularJS Select Element

I have been experimenting with AngularJS, and while I like it a lot overall, there have definitely been some rough patches along the way. The last problem I dealt with, I had a tricky time getting a select element to work the way I wanted.  Once I got it working, the solution makes sense, and the documentation makes sense as well. However, before I got it working the documentation didn’t help me out at all.

Here’s my scenario: I have a list of objects, loaded into my model via an HTTP call. These are competitors from the 59th All Japan Kendo Tournament in 2011.

 
   [
      {
        "competitor_number": 4,
        "name": "Kinoshita Tomonari",
        "age": 28,
        "grade": "5-dan",
        "entryCount": "2",
        "occupation": "Police Officer",
        "prefecture": "Kagawa"
      },
      ...
    ]

When setting up an edit form for adding or manipulating competitor records, the prefecture property is a perfect candidate for a select component – like US states, Japanese prefectures are a well defined set of values. I fetch the list of prefectures via another HTTP call.

[
    {"name":"Hokkaido"},
    {"name":"Aomori"},
    {"name":"Iwate"},
    {"name":"Miyagi"},
    {"name":"Akita"},
    ...
]

Setting up the the Angular select element to show this list of values is very straightforward.

<select ng-model="entry.prefecture" ng-options="p.name for p in prefectures">
</select>

This gives, as you’d expect, a pulldown menu with the list of prefectures as values. The catch is, how to make the select correctly set the selected option based on the value in the entry object?

The AngularJS documentation gives several forms for the comprehension expression:

  • label for value in array
  • select as label for value in array
  • label group by group for value in array
  • select as label group by group for value in array

In this case, the one we need is the second. This is where the documentation gets a little confusing:

  • select: The result of this expression will be bound to the model of the parent element. If not specified, select expression will default to value.

What this is saying, is that this expression should match up with the value contained in your model. The select element has an ng-model property, and the value of this model is compared against the value of this expression. If nothing is specified, the entire value (in this case, a full object) will be used. So to have the entry.prefecture property compared against the p.name property from the prefecture list, we need the following:

<select ng-model="entry.prefecture" 
  ng-options="p.name as p.name for p in prefectures">
</select>

In this comprehension, p.name is used for the match, p.name is used for the text to display in the pulldown, p is the individual element, and prefectures is the source array. For this example, we want the pulldown values to match with the value in the model as a string, but this formulation would let us match on some other value, for example, storing an id value in the model but displaying some full text in the pulldown.

I’m sure this won’t be the last time I will get hung up on something in the AngularJS docs. This is a good example that many of these hangups may stem from the writing being clear once you have a basic grasp but unclear if you are on the learning side. It’s always hard when writing or speaking (or, even testing), to keep beginner mind and ensure that your content addresses your audience where they are, not where you are.

Kero.

Advertisements