ChatGPT解决这个技术问题 Extra ChatGPT

How do I set the value property in AngularJS' ng-options?

Here is what seems to be bothering a lot of people (including me).

When using the ng-options directive in AngularJS to fill in the options for a <select> tag, I cannot figure out how to set the value for an option. The documentation for this is really unclear - at least for a simpleton like me.

I can set the text for an option easily like so:

ng-options="select p.text for p in resultOptions"

When resultOptions is for example:

[
    {
        "value": 1,
        "text": "1st"
    },
    {
        "value": 2,
        "text": "2nd"
    }
]

It should be (and probably is) the most simple thing to set the option values, but so far I just don't get it.

Had the same problem because I didn't find the docs (as shown below) very clear.
The use of "select" as it is depicted in the question is essentially wrong, because "select" in this context, is not a keyword, but it is a place holder for an expression. This is from AngularJS' documentation: "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." I have provide more detail in my answer below.
For me this is the best answer. stackoverflow.com/questions/12139152/…
Note: For ng-options to work, ng-model is mandatory!!!!!!!!! Ref:stackoverflow.com/a/13049740/234110

D
Dan Atkinson

See ngOptions ngOptions(optional) – {comprehension_expression=} – in one of the following forms: For array data sources: 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 track by trackexpr For object data sources: label for (key , value) in object select as label for (key , value) in object label group by group for (key, value) in object select as label group by group for (key, value) in object

In your case, it should be

array = [{ "value": 1, "text": "1st" }, { "value": 2, "text": "2nd" }];

<select ng-options="obj.value as obj.text for obj in array"></select>

Update

With the updates on AngularJS, it is now possible to set the actual value for the value attribute of select element with track by expression.

<select ng-options="obj.text for obj in array track by obj.value">
</select>

How to remember this ugly stuff

To all the people who are having hard time to remember this syntax form: I agree this isn't the most easiest or beautiful syntax. This syntax is kind of an extended version of Python's list comprehensions and knowing that helps me to remember the syntax very easily. It's something like this:

Python code:

my_list = [x**2 for x in [1, 2, 3, 4, 5]]
> [1, 4, 9, 16, 25]

# Let people to be a list of person instances
my_list2 = [person.name for person in people]
> my_list2 = ['Alice', 'Bob']

This is actually the same syntax as the first one listed above. However, in <select> we usually need to differentiate between the actual value in code and the text shown (the label) in a <select> element.

Like, we need person.id in the code, but we don't want to show the id to the user; we want to show its name. Likewise, we're not interested in the person.name in the code. There comes the as keyword to label stuff. So it becomes like this:

person.id as person.name for person in people

Or, instead of person.id we could need the person instance/reference itself. See below:

person as person.name for person in people

For JavaScript objects, the same method applies as well. Just remember that the items in the object is deconstructed with (key, value) pairs.


Your example doesn't fill value attribute of option. It defines what would be stored in the model of <select> element. See difference between obj.value as obj.text and obj.text
Strange but I get , in Chrome and FF.
It's not bug, it's a feature. angularjs handles ngOptions and ngModel internally, this way it allows you to use any type of object as value in option rather than only strings. You should never try to get the value of the select the other way around you just need to use ngModel you attached to select element.
I beg to differ. Internally the select directive could easily use its own invisible model to track which option is selected. Even if it didn't track the model value internally, it could at least render the options and just prepend and select the empty option (which is the behavior that it does now if you set the model to a value not in the option set). The only dependency for showing options is the options themselves -- POLA principle applies here.
Why does this answer have so many up votes when it does not provide the answer? frm.adiputra's answer is correct.
P
Peter Mortensen

How the value attributes gets its value:

When using an array as datasource, it will be the index of the array element in each iteration;

When using an object as datasource, it will be the property name in each iteration.

So in your case it should be:

obj = { '1': '1st', '2': '2nd' };

<select ng-options="k as v for (k,v) in obj"></select>

+1 for explaining how Angular sets the value attribute of the option elements.
This does not set a value. Values default to numbers. But you can't actually specify a "value".. rediculous..
@Trip, if you 'inspect' the select options, you will see numbers, but if you look at the bound value in the model, the value is in this case the 'k' value. It's confusing. blesh has a plunk that shows this in this answer: stackoverflow.com/questions/13047923/… plnkr.co/edit/vJOljg?p=preview
This is should be included into the angular document, short and precise. +1
This is the only solution that worked for me. What a nasty headache.
C
Community

I had this issue too. I wasn't able to set my value in ng-options. Every option that was generated was set with 0, 1, ..., n.

To make it right, I did something like this in my ng-options:

HTML:

<select ng-options="room.name for room in Rooms track by room.price">
    <option value="">--Rooms--</option>
</select>

I use "track by" to set all my values with room.price.

(This example sucks: because if there were more than one price equal, the code would fail. So BE SURE to have different values.)

JSON:

$scope.Rooms = [
            { name: 'SALA01', price: 100 },
            { name: 'SALA02', price: 200 },
            { name: 'SALA03', price: 300 }
        ];

I learned it from blog post How to set the initial selected value of a select element using Angular.JS ng-options & track by.

Watch the video. It's a nice class :)


This works perfectly. On top of it, it allows to use a datalist element with a contained . What you have works, but it won't work with other Angular constructs. E.g., this ng-click won't work with your code: select 1, but it does work if ng-options is used.
I just had a strange bug show up because of doing it this way. Lots of pained searching brought me to the discovery of ng-options, and the bug disappeared. The ng-model seems to require that the value attribute of the options is numerical and ascending from 0. If you change the value to a non numerical index by using ng-repeat and
J
Jeffrey A. Gochin

I have struggled with this problem for a while today. I read through the AngularJS documentation, this and other posts and a few of blogs they lead to. They all helped me grock the finer details, but in the end this just seems to be a confusing topic. Mainly because of the many syntactical nuances of ng-options.

In the end, for me, it came down to less is more.

Given a scope configured as follows:

        //Data used to populate the dropdown list
        $scope.list = [
           {"FirmnessID":1,"Description":"Soft","Value":1},         
           {"FirmnessID":2,"Description":"Medium-Soft","Value":2},
           {"FirmnessID":3,"Description":"Medium","Value":3}, 
           {"FirmnessID":4,"Description":"Firm","Value":4},     
           {"FirmnessID":5,"Description":"Very Firm","Value":5}];

        //A record or row of data that is to be save to our data store.
        //FirmnessID is a foreign key to the list specified above.
        $scope.rec = {
           "id": 1,
           "FirmnessID": 2
        };

This is all I needed to get the desired result:

        <select ng-model="rec.FirmnessID"
                ng-options="g.FirmnessID as g.Description for g in list">
            <option></option>
        </select>   

Notice I did not use track by. Using track by the selected item would alway return the object that matched the FirmnessID, rather than the FirmnessID itself. This now meets my criteria, which is that it should return a numeric value rather than the object, and to use ng-options to gain the performance improvement it provides by not creating a new scope for each option generated.

Also, I needed the blank first row, so I simply added an <option> to the <select> element.

Here is a Plunkr that shows my work.


Legend. This is exactly what I needed. Thankyou
Great, but what's the purpose of the "Value" keys? They don't seem to be necessary.
Not relevant to the example. They are simply part of the original data provided to me by my client.
K
KthProg

Instead of using the new 'track by' feature you can simply do this with an array if you want the values to be the same as the text:

<select ng-options="v as v for (k,v) in Array/Obj"></select>

Note the difference between the standard syntax, which will make the values the keys of the Object/Array, and therefore 0,1,2 etc. for an array:

<select ng-options"k as v for (k,v) in Array/Obj"></select>

k as v becomes v as v.

I discovered this just based on common sense looking at the syntax. (k,v) is the actual statement that splits the array/object into key value pairs.

In the 'k as v' statement, k will be the value, and v will be the text option displayed to the user. I think 'track by' is messy and overkill.


Waaaaat? Works for arrays all over the place on my pages, are we using the same version of AngularJS?
P
Peter Mortensen

This was best suited for all scenarios according to me:

<select ng-model="mySelection.value">
   <option ng-repeat="r in myList" value="{{r.Id}}" ng-selected="mySelection.value == r.Id">{{r.Name}}
   </option>
</select>

where you can use your model to bind the data. You will get the value as the object will contain and the default selection based on your scenario.


Love this solution. Their angular helpers for this directive are unnecessarily complex. Thanks for being the self proclaimed judge of usage.
P
Peter Mortensen

This is how I resolved this. I tracked the select by value and set the selected item property to the model in my JavaScript code.

Countries =
[
    {
        CountryId = 1, Code = 'USA', CountryName = 'United States of America'
    },
    {
       CountryId = 2, Code = 'CAN', CountryName = 'Canada'
    }
]
<select ng-model="vm.Enterprise.AdminCountry" ng-options="country.CountryName for country in vm.Countries track by country.CountryId">

vm is my controller and the Country in the controller retrieved from the service is {CountryId =1, Code = 'USA', CountryName='United States of America'}.

When I selected another country from the select dropdown and posted my page with "Save", I got the correct country bound.


C
Community

The ng-options directive does not set the value attribute on the <options> elements for arrays:

Using limit.value as limit.text for limit in limits means:

set the

See Stack Overflow question AngularJS ng-options not rendering values.


W
Wessam Al-Bakary

You can use ng-options to achieve select tag binding to value and display members

While using this data source

countries : [
              {
                 "key": 1,
                 "name": "UAE"
             },
              {
                  "key": 2,
                  "name": "India"
              },
              {
                  "key": 3,
                  "name": "OMAN"
              }
         ]

you can use the below to bind your select tag to value and name

<select name="text" ng-model="name" ng-options="c.key as c.name for c in countries"></select>

it works great


Please augment your code-only answer with some explanation, in order to avoid the misconception that StackOverflow is a free code writing service.
A
Anja Ishmukhametova
<select ng-model="color" ng-options="(c.name+' '+c.shade) for c in colors"></select><br>

A
Aleks

A year after the question, I had to find an answer for this question as non of these gave the actual answer, at least to me.

You have asked how to select the option, but nobody has said that these two things are NOT the same:

If we have an options like this:

$scope.options = [
    { label: 'one', value: 1 },
    { label: 'two', value: 2 }
  ];

And we try to set a default option like this:

$scope.incorrectlySelected = { label: 'two', value: 2 };

It will NOT work, but if you try to select the option like this:

$scope.correctlySelected = $scope.options[1];

It will WORK.

Even though these two objects have the same properties, AngularJS is considering them as DIFFERENT because AngularJS compares by the reference.

Take a look at the fiddle http://jsfiddle.net/qWzTb/.


C
Community

The correct answer to this question has been provided by user frm.adiputra, as currently this seems to be the only way to explicitly control the value attribute of the option elements.

However, I just wanted to emphasize that "select" is not a keyword in this context, but it is just a placeholder for an expression. Please refer to the following list, for the definition of the "select" expression as well as other expressions that can be used in ng-options directive.

The use of select as it is depicted in the question:

ng-options='select p.text for p  in resultOptions'

is essentially wrong.

Based on the list of expressions, it seems that trackexpr may be used to specify the value, when options are given in an array of objects, but it has been used with grouping only.

From AngularJS' documentation for ng-options:

array / object: an expression which evaluates to an array / object to iterate over.

value: local variable which will refer to each item in the array or each property value of object during iteration.

key: local variable which will refer to a property name in object during iteration.

label: The result of this expression will be the label for element. The expression will most likely refer to the value variable (e.g. value.propertyName).

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.

group: The result of this expression will be used to group options using the DOM element.

trackexpr: Used when working with an array of objects. The result of this expression will be used to identify the objects in the array. The trackexpr will most likely refer to the value variable (e.g. value.propertyName).


P
Peter Mortensen

Selecting an item in ng-options can be a bit tricky depending on how you set the data source.

After struggling with them for a while I ended up making a sample with most common data sources I use. You can find it here:

http://plnkr.co/edit/fGq2PM?p=preview

Now to make ng-options work, here are some things to consider:

Normally you get the options from one source and the selected value from other. For example: states :: data for ng-options user.state :: Option to set as selected Based on 1, the easiest/logical thing to do is to fill the select with one source and then set the selected value trough code. Rarely would it be better to get a mixed dataset. AngularJS allows select controls to hold more than key | label. Many online examples put objects as 'key', and if you need information from the object set it that way, otherwise use the specific property you need as key. (ID, CODE, etc.. As in the plckr sample) The way to set the value of the dropdown/select control depends on #3, If the dropdown key is a single property (like in all examples in the plunkr), you just set it, e.g.: $scope.dropdownmodel = $scope.user.state; If you set the object as key, you need to loop trough the options, even assigning the object will not set the item as selected as they will have different hashkeys, e.g.: for (var i = 0, len = $scope.options.length; i < len; i++) { if ($scope.options[i].id == savedValue) { // Your own property here: console.log('Found target! '); $scope.value = $scope.options[i]; break; } }

You can replace savedValue for the same property in the other object, $scope.myObject.myProperty.


over a years later, I thank you for the plunker sample. Very useful.
C
Community

For me the answer by Bruno Gomes is the best answer.

But actually, you need not worry about setting the value property of select options. AngularJS will take care of that. Let me explain in detail.

Please consider this fiddle

angular.module('mySettings', []).controller('appSettingsCtrl', function ($scope) {

    $scope.timeFormatTemplates = [{
        label: "Seconds",
        value: 'ss'
    }, {
        label: "Minutes",
        value: 'mm'
    }, {
        label: "Hours",
        value: 'hh'
    }];


    $scope.inactivity_settings = {
        status: false,
        inactive_time: 60 * 5 * 3, // 15 min (default value), that is, 900 seconds
        //time_format: 'ss', // Second (default value)
        time_format: $scope.timeFormatTemplates[0], // Default seconds object
    };

    $scope.activity_settings = {
        status: false,
        active_time: 60 * 5 * 3, // 15 min (default value), that is,  900 seconds
        //time_format: 'ss', // Second (default value)
        time_format: $scope.timeFormatTemplates[0], // Default seconds object
    };

    $scope.changedTimeFormat = function (time_format) {
        'use strict';

        console.log('time changed');
        console.log(time_format);
        var newValue = time_format.value;

        // do your update settings stuffs
    }
});

As you can see in the fiddle output, whatever you choose for select box options, it is your custom value, or the 0, 1, 2 auto generated value by AngularJS, it does not matter in your output unless you are using jQuery or any other library to access the value of that select combo box options and manipulate it accordingly.


S
Shashank Saxena

Please use track by property which differentiate values and labels in select box.

Please try

<select ng-options="obj.text for obj in array track by obj.value"></select>

which will assign labels with text and value with value(from the array)


E
EpokK

For an object:

<select ng-model="mySelect" ng-options="key as value for (key, value) in object"></select>

C
Community

It is always painful for developers to with ng-options. For example: Getting an empty/blank selected value in the select tag. Especially when dealing with JSON objects in ng-options, it becomes more tedious. Here I have done some exercises on that.

Objective: Iterate array of JSON objects through ng-option and set selected first element.

Data:

someNames = [{"id":"1", "someName":"xyz"}, {"id":"2", "someName":"abc"}]

In the select tag I had to show xyz and abc, where xyz must be selected without much effort.

HTML:

<pre class="default prettyprint prettyprinted" style=""><code>
    &lt;select class="form-control" name="test" style="width:160px"    ng-options="name.someName for name in someNames" ng-model="testModel.test" ng-selected = "testModel.test = testModel.test || someNames[0]"&gt;
&lt;/select&gt;
</code></pre>

By above code sample, you might get out of this exaggeration.

Another reference:


P
Peter Mortensen

The tutorial ANGULAR.JS: NG-SELECT AND NG-OPTIONS helped me solve the problem:

<select id="countryId"
  class="form-control"
  data-ng-model="entity.countryId"
  ng-options="value.dataValue as value.dataText group by value.group for value in countries"></select>

e
ethanneff
<select ng-model="output">
   <option ng-repeat="(key,val) in dictionary" value="{{key}}">{{val}}</option>
</select>

ngOptions provides some benefits such as reducing memory and increasing speed by not creating a new scope for each repeated instance, see: docs.angularjs.org/api/ng/directive/ngOptions
P
Premchandra Singh

Run the code snippet and see the variations. Here is note for quick understanding

Example 1(Object selection):- ng-option="os.name for os in osList track by os.id". Here track by os.id is important & should be there and os.id as should NOT have before os.name. The ng-model="my_os" should set to an object with key as id like my_os={id: 2}. Example 2(Value selection) :- ng-option="os.id as os.name for os in osList". Here track by os.id should NOT be there and os.id as should be there before os.name. The ng-model="my_os" should set to a value like my_os= 2

Rest code snippet will explain.

angular.module('app', []).controller('ctrl', function($scope, $timeout){ //************ EXAMPLE 1 ******************* $scope.osList =[ { id: 1, name :'iOS'}, { id: 2, name :'Android'}, { id: 3, name :'Windows'} ] $scope.my_os = {id: 2}; //************ EXAMPLE 2 ******************* $timeout(function(){ $scope.siteList = [ { id: 1, name: 'Google'}, { id: 2, name: 'Yahoo'}, { id: 3, name: 'Bing'} ]; }, 1000); $scope.my_site = 2; $timeout(function(){ $scope.my_site = 3; }, 2000); }) fieldset{ margin-bottom: 40px; } strong{ color:red; }

Example 1 (Set selection as object) {{my_os}}
Example 2 (Set selection as value. Simulate ajax) {{my_site}}


P
Peter Mortensen

Like many said before, if I have data something like this:

countries : [
              {
                 "key": 1,
                 "name": "UAE"
             },
              {
                  "key": 2,
                  "name": "India"
              },
              {
                  "key": 3,
                  "name": "OMAN"
              }
         ]

I would use it like:

<select
    ng-model="selectedCountry"
    ng-options="obj.name for obj  in countries">
</select>

In your Controller you need to set an initial value to get rid of the first empty item:

 $scope.selectedCountry = $scope.countries[0];

 // You need to watch changes to get selected value
 $scope.$watchCollection(function() {
   return $scope.selectedCountry
 }, function(newVal, oldVal) {
     if (newVal === oldVal) {
       console.log("nothing has changed " + $scope.selectedCountry)
     } 
     else {
       console.log('new value ' + $scope.selectedCountry)
     }
 }, true)

P
Peter Mortensen

Here is how I solve this problem in a legacy application:

In HTML:

ng-options="kitType.name for kitType in vm.kitTypes track by kitType.id" ng-model="vm.itemTypeId"

In JavaScript:

vm.kitTypes = [
    {"id": "1", "name": "Virtual"},
    {"id": "2", "name": "Physical"},
    {"id": "3", "name": "Hybrid"}
];

...

vm.itemTypeId = vm.kitTypes.filter(function(value, index, array){
    return value.id === (vm.itemTypeId || 1);
})[0];

My HTML displays the option value properly.


M
Masud Shrabon

ngOptions directive:

$scope.items = [{name: 'a', age: 20},{ name: 'b', age: 30},{ name: 'c', age: 40}];

Case-1) label for value in array:

selected item is : {{selectedItem}}

age of selected item is : {{selectedItem.age}}

Output Explanation (Assume 1st item selected):

selectedItem = {name: 'a', age: 20} // [by default, selected item is equal to the value item]

selectedItem.age = 20

Case-2) select as label for value in array:

selected item is : {{selectedItem}}

Output Explanation (Assume 1st item selected): selectedItem = 20 // [select part is item.age]