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 &
It appears that ng-options
is complicated (possibly frustrating) to use, but in reality we have an architecture problem.
AngularJS serves as an MVC framework for a dynamic HTML+JavaScript application. While its (V)iew component does offer HTML "templating," its primary purpose is to connect user actions, via a controller, to changes in the model. Therefore the appropriate level of abstraction, from which to work in AngularJS, is that a select element sets a value in the model to a value from a query.
ng-options
provides the for
keyword to dictate what the contents of the option element should be i.e. p.text for p in resultOptions
.ng-options
provides the as
keyword to specify what value is provided to the model as in k as v for (k,v) in objects
.The correct solution this is problem is then architectural in nature and involves refactoring your HTML so that the (M)odel performs server communication when required (instead of the user submitting a form).
If an MVC HTML page is unnecessary over-engineering for the problem at hand: then use only the HTML generation portion of AngularJS’s (V)iew component. In this case, follow the same pattern that is used for generating elements such as <li />
's under <ul />
's and place a ng-repeat on an option element:
<select name=“value”>
<option ng-repeat=“value in Model.Values” value=“{{value.value}}”>
{{value.text}}
</option>
</select>
As kludge, one can always move the name attribute of the select element to a hidden input element:
<select ng-model=“selectedValue” ng-options=“value.text for value in Model.Values”>
</select>
<input type=“hidden” name=“value” value=“{{selectedValue}}” />
$scope.items = [{name: 'a', age: 20},{ name: 'b', age: 30},{ name: 'c', age: 40}];
Case-1) label for value in array:
<div>
<p>selected item is : {{selectedItem}}</p>
<p> age of selected item is : {{selectedItem.age}} </p>
<select ng-model="selectedItem" ng-options="item.name for item in items">
</select>
</div>
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:
<div>
<p>selected item is : {{selectedItem}}</p>
<select ng-model="selectedItem" ng-options="item.age as item.name for item in items">
</select>
</div>
Output Explanation (Assume 1st item selected): selectedItem = 20 // [select part is item.age]
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.
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 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)
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/.