[javascript] Working with select using AngularJS's ng-options

I have read about it in other posts, but I couldn't figure it out.

I have an array,

$scope.items = [
   {ID: '000001', Title: 'Chicago'},
   {ID: '000002', Title: 'New York'},
   {ID: '000003', Title: 'Washington'},
];

I want to render it as:

<select>
  <option value="000001">Chicago</option>
  <option value="000002">New York</option>
  <option value="000003">Washington</option>
</select>

And also I want to select the option with ID=000002.

I have read select and tried, but I can't figure it out.

This question is related to javascript angularjs html-select ng-options

The answer is


If you need a custom title for each option, ng-options is not applicable. Instead use ng-repeat with options:

<select ng-model="myVariable">
  <option ng-repeat="item in items"
          value="{{item.ID}}"
          title="Custom title: {{item.Title}} [{{item.ID}}]">
       {{item.Title}}
  </option>
</select>

I hope the following will work for you.

<select class="form-control"
        ng-model="selectedOption"
        ng-options="option.name + ' (' + (option.price | currency:'USD$') + ')' for option in options">
</select>

In CoffeeScript:

#directive
app.directive('select2', ->
    templateUrl: 'partials/select.html'
    restrict: 'E'
    transclude: 1
    replace: 1
    scope:
        options: '='
        model: '='
    link: (scope, el, atr)->
        el.bind 'change', ->
            console.log this.value
            scope.model = parseInt(this.value)
            console.log scope
            scope.$apply()
)
<!-- HTML partial -->
<select>
  <option ng-repeat='o in options'
          value='{{$index}}' ng-bind='o'></option>
</select>

<!-- HTML usage -->
<select2 options='mnuOffline' model='offlinePage.toggle' ></select2>

<!-- Conclusion -->
<p>Sometimes it's much easier to create your own directive...</p>

I'm learning AngularJS and was struggling with selection as well. I know this question is already answered, but I wanted to share some more code nevertheless.

In my test I have two listboxes: car makes and car models. The models list is disabled until some make is selected. If selection in makes listbox is later reset (set to 'Select Make') then the models listbox becomes disabled again AND its selection is reset as well (to 'Select Model'). Makes are retrieved as a resource while models are just hard-coded.

Makes JSON:

[
{"code": "0", "name": "Select Make"},
{"code": "1", "name": "Acura"},
{"code": "2", "name": "Audi"}
]

services.js:

angular.module('makeServices', ['ngResource']).
factory('Make', function($resource){
    return $resource('makes.json', {}, {
        query: {method:'GET', isArray:true}
    });
});

HTML file:

<div ng:controller="MakeModelCtrl">
  <div>Make</div>
  <select id="makeListBox"
      ng-model="make.selected"
      ng-options="make.code as make.name for make in makes"
      ng-change="makeChanged(make.selected)">
  </select>

  <div>Model</div>
  <select id="modelListBox"
     ng-disabled="makeNotSelected"
     ng-model="model.selected"
     ng-options="model.code as model.name for model in models">
  </select>
</div>

controllers.js:

function MakeModelCtrl($scope)
{
    $scope.makeNotSelected = true;
    $scope.make = {selected: "0"};
    $scope.makes = Make.query({}, function (makes) {
         $scope.make = {selected: makes[0].code};
    });

    $scope.makeChanged = function(selectedMakeCode) {
        $scope.makeNotSelected = !selectedMakeCode;
        if ($scope.makeNotSelected)
        {
            $scope.model = {selected: "0"};
        }
    };

    $scope.models = [
      {code:"0", name:"Select Model"},
      {code:"1", name:"Model1"},
      {code:"2", name:"Model2"}
    ];
    $scope.model = {selected: "0"};
}

The question is already answered (BTW, really good and comprehensive answer provided by Ben), but I would like to add another element for completeness, which may be also very handy.

In the example suggested by Ben:

<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>

the following ngOptions form has been used: select as label for value in array.

Label is an expression, which result will be the label for <option> element. In that case you can perform certain string concatenations, in order to have more complex option labels.

Examples:

  • ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" gives you labels like Title - ID
  • ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items" gives you labels like Title (X), where X is length of Title string.

You can also use filters, for example,

  • ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items" gives you labels like Title (TITLE), where Title value of Title property and TITLE is the same value but converted to uppercase characters.
  • ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items" gives you labels like Title (27 Sep 2015), if your model has a property SomeDate

It can be useful. Bindings do not always work.

<select id="product" class="form-control" name="product" required
        ng-model="issue.productId"
        ng-change="getProductVersions()"
        ng-options="p.id as p.shortName for p in products"></select>

For example, you fill the options list source model from a REST service. A selected value was known before filling the list, and it was set. After executing the REST request with $http, the list option is done.

But the selected option is not set. For unknown reasons AngularJS in shadow $digest executing does not bind selected as it should be. I have got to use jQuery to set the selected. It`s important! AngularJS, in shadow, adds the prefix to the value of the attr "value" for generated by ng-repeat options. For int it is "number:".

$scope.issue.productId = productId;
function activate() {
    $http.get('/product/list')
       .then(function (response) {
           $scope.products = response.data;

           if (productId) {
               console.log("" + $("#product option").length);//for clarity
               $timeout(function () {
                   console.log("" + $("#product option").length);//for clarity
                   $('#product').val('number:'+productId);

               }, 200);
           }
       });
}

For some reason AngularJS allows to get me confused. Their documentation is pretty horrible on this. More good examples of variations would be welcome.

Anyway, I have a slight variation on Ben Lesh's answer.

My data collections looks like this:

items =
[
   { key:"AD",value:"Andorra" }
,  { key:"AI",value:"Anguilla" }
,  { key:"AO",value:"Angola" }
 ...etc..
]

Now

<select ng-model="countries" ng-options="item.key as item.value for item in items"></select>

still resulted in the options value to be the index (0, 1, 2, etc.).

Adding Track By fixed it for me:

<select ng-model="blah" ng-options="item.value for item in items track by item.key"></select>

I reckon it happens more often that you want to add an array of objects into an select list, so I am going to remember this one!

Be aware that from AngularJS 1.4 you can't use ng-options any more, but you need to use ng-repeat on your option tag:

<select name="test">
   <option ng-repeat="item in items" value="{{item.key}}">{{item.value}}</option>
</select>

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature

Examples related to html-select

How can I get new selection in "select" in Angular 2? How to show disable HTML select option in by default? Remove Select arrow on IE Bootstrap 3 select input form inline Change <select>'s option and trigger events with JavaScript How to use a Bootstrap 3 glyphicon in an html select Creating a select box with a search option Drop Down Menu/Text Field in one How to have a default option in Angular.js select box How to set the 'selected option' of a select dropdown list with jquery

Examples related to ng-options

ng-change get new value and original value Setting selected values for ng-options bound select elements ng-options with simple array init Working with select using AngularJS's ng-options