The right way to use track by with ng-options in Angular 1.4 & 1.5 — Why can’t I select this option?

There is a change in the way AngularJS tracks each option of the select element that was released as part of Angular 1.4.

Instead of using the index of each item in your list when you don’t use track by and using the value pased to track by when you use it, it will use an object hash of the item or track by property.

If you are using track by with ng-options, and using it correctly, this change will not affect you. Otherwise, you may get some interesting side effects. Let’s see what this means.

Let’s assume the following model:

You notice that the first element has a simple key of number type. The others have different objects as their keys.

What would be the effect of that in Angular 1.4?

Without “track by”

Given the HTML:

Angular Will generate:

(I have formatted the generated HTML for easy read)

Angular uses the a hash of the object as its key. For items in the list used without track by we get the useless object bit, followed by a number that seems unique, but isn’t the index of the element for example.

Of course we also get the empty element added as we didn’t select an initial value. I talked about this before in detail here.

With “track by”

If we change our HTML to:

Where we tell Angular to differentiate between the items in the list by their key property, we get the following HTML generated in runtime:

Ignoring the first item and tabs and form classes again, and only looking at the value attribute of each option tag, we notice the following:

The generated hash code for the simple number value (key: 1), was the value itself, 1.

The generated hash code for the objects, was just what you’d get if you write the object in an old browser console log, a silly useless [object Object].

Why does this matter?

Try to select item “Two” from this example (in Chrome, for example):

You can’t.

Because both item 2 and item 3 have the same value string [object Object].

Here’s the code to play with.

What to learn from this

I’d say, we have two best practices when using select and ng-options with AngularJS:

  • Always use track by
  • Always set your key to a simple value, a string or a number

This will save you too much trouble.

Share With Friends:

P.S. Please help me out by checking this offer, then look below for a small Thank You.

How did I learn that?

As a bonus for coming here, I'm giving away a free newsletter for web developers that you can sign up for from here.
It's not an anything-and-everything link list. It's thoughtfully collected picks of articles and tools, that focus on Angular 2, ASP.NET 5, and other fullstack developer goodies.

  • Nice article, it helped me a lot!! Thank you very much :)


  • Lucas Gabriel

    how to use track by + filter or + disable when?

    I have a problem. in a system I’m developing I have to upload files. each file must be of a given “category” and only ONE file per category. so when the user uploads the file I show a ng-select and the options are an array. I want when the user select one item from one select the other select boxes will prevent the user from selecting that same option again. I can do it easily with a filter and some functions or even easier with some functions and disable when. the problem however remains in tracking the selected option and binding it to an object that I intend on saving in database u see.

  • bondarewicz

    I’ve noticed that even if using track by there is something else going on with comparison, imaging data from api containing only a key, then locally a list of options for select containing key & text, setting a model to a key doesn’t set “selected” option… any ideas?