ngOptions result in options with wrong values - angularjs

I'm trying to render select box and it does not work as expected - options values are incorrect. I checked manual, according to it the syntax for array (in my case array of objects) is
select as label for value in array
So here is what i'm doing:
data:
[{"id":"3","name":"asdasd","code":"asdads","group":"2","cost":"0"},{"id":"4","name":"adrf fg df ","code":"dasfasd","group":"2","cost":"0"}]
template:
<select ng-model="productToBuy" ng-options="item.id as item.id for item in products"></select>
rendered result:
<select ng-model="productToBuy" ng-options="item.id as item.id for item in products" class="ng-pristine ng-valid">
<option value="0" selected="selected">3</option>
<option value="1">4</option>
</select>
as we can see, options values does not set to items's id.
Also this may be not proper syntax when source is array but i having same results when trying like this:
<select ng-model="productToBuy" ng-options="item.id as item.id for (key, item) in products"></select>
I put this code on jsfiddle. Any help appreciated.

This is the behavior of the ngOptions directive (the output you are seeing, where the value is the index of the item and not the id property that you are trying to pass in from your code sample). ngOptions will data-bind the selected option to the variable that you specified in ngModel. You would then work with your data bound variable instead of the "value" of the option element itself.
Html:
<select ng-model="selected" ng-options="item.name for item in items"></select> {{ selected }}
JS:
$scope.items = [
{"id": "3","name":"asdasd","code":"asdads","group":"2","cost":"0"},
{"id": "4","name":"adrf fg df ","code":"dasfasd","group":"2","cost":"0"}
];
In the above example, $scope.selected would represent the actual selected item. You can then access any of the selected item's properties: $scope.selected.name, $scope.selected.code... etc.
If you needed to preselect an item with the above example, you could do the following:
$scope.items = [
{"id": "3","name":"asdasd","code":"asdads","group":"2","cost":"0"},
{"id": "4","name":"adrf fg df ","code":"dasfasd","group":"2","cost":"0"}
];
$scope.selected = $scope.items[1]; // Pre-selected the 2nd item in your array
If you still need to have full control over your value attributes, you're better off using the ng-repeat directive, but remember if you do this, your selected items won't be data bound to your model.
EDIT: Note on 'select as label for value in array' syntax:
In case its helpful, what your "item.id as item.name for item in products" was doing was actually setting your variable in the ngModel directive to the value you specify in the select portion of the syntax. So what that expression is doing is setting the label as item.name, but binding $scope.selected to the value of item.id, rather than to the entire instance of item itself. So if your first item in the examples above was selected, $scope.selected would be equal to "3". It doesn't actually change the value attribute of the option element itself.

Your datatype in the JSON object for the id is a string and the value of $scope.selected is integer. If you switch one of them to the other it would work fine!
The value of the options will still be 0 and 1, but the databinding of Angular does the trick for you and binds the value you have specified in your expression (item.id as item.name) to the ng-model of your parent element (the select element).

If you don't need ng-model of select element and you want to use selected value of select element, then implement it in this way:
<select>
<option ng-repeat="item in items" value="{{item.value}}">
{{item.text}}
</option>
</select>

Related

Using AngularJS select element to set a variable to an object instead of a string

The following code works. My question is whether this is the right way to do it.
The variable devices is an array of objects and when the user selects one the variable selDev gets set to one of those objects. If I make selDev the model via the ng-model attribute then it gets a string, not the original model.
<p>
<label>Device Id:</label>
<select ng-model="selDevIndex"
ng-change="selDev = devices[selDevIndex]">
<option value="">(no device)</option>
<option ng-repeat="device in devices "
value="{{$index}}">
{{device.id}}: {{device.type}} {{device.mfr}}
{{device.serial}}
</option>
</select>
</p>
I find this a little clumsy due to the inclusion of the $index reference. Also this technique would not work if devices was an object an not an array. Is there a better way?
You can use ng-options
HTML:
<select ng-model="selectedModel"
ng-options="device as device.text for device in devices track by device.id">
</select>
CONTROLLER:
$scope.selectedModel;
$scope.devices = [{
id: 1,
text: "Device1"
}, {
id: 2,
text: "Device2"
}];
Check this jsFiddle
If you have to loop over an object instead of an array, check this post

dropdown is not populating with json object

my ng-model value is - "{"Id":1,"Description":"Draft","Code":"Draft"}" and ng-options are -
[
{
"Id": 1,
"Description": "Draft",
"Code": "Draft"
},
{
"Id": 2,
"Description": "UserSubmitted",
"Code": "UserSubmitted"
},
{
"Id": 3,
"Description": "PLMApproved",
"Code": "PLMApproved"
}
]
so my dropdown is not populating(but value is binding).
I understatnd, if ng-model values is just a integer value it would bind, then how about json object?
Please help needed.
AFAIK it won't bind because your model is a different object i.e. points to a different memory location and it doesn't match with any objects inside the array.
You could use the as clause in ng-options to select a property you want to get into the ng-model and setting ng-model with that value will set the selected option.
e.g.
<select ng-options="item.Id as item.Description for item in default.items" ng-model="default.selectedItemId">
<option value="">Select</option>
</select>
else you could use the track by clause which is used when you want to get one property or object into your ng-model but you want to set the selected option with another property from the ng-model which will be specified in the track by clause i.e. update the binding from code to the view
e.g.
<select ng-options="item as item.Description for item in default.items track by item.Id" ng-model="default.selectedItem">
<option value="">Select</option>
</select>

Angular Formly - Select input with object

Please look at the following jsbin. I have a select input that has two options (Ohio, NewYork). Within the ng-options for the Select, I am selecting the entire object and NOT just the name or key value. I need both.
When I select Ohio (for example), the model correctly updates showing the selected object:
"birthState": {
"Key": "1",
"Value": "Ohio"
}
If I add this code to the model within my controller (setting the field to 'Ohio' by default), the select does not reflect this default setting.
What am I doing wrong that is preventing me from giving this dropdown a default value?
You are not able to select because, all objects will have unique id. objects in options array and object assigned in model (in controller) will be different in this way.
To achieve what you wanted, try adding track by option.Key in ng-options, and assign Key for 'birthState' field of model inside controller.
<script type="text/ng-template" id="select.html">
<select required type="number" ng-model="model[options.key]" ng-options="option.Value for option in to.options track by option.Key">
<option value="">Select One</option>
</select>
</script>
inside controller
vm.model = {
"birthState": {Key: '3'}
};

angularjs - pass selected object's other properties on ng-change

How can I get other properties from loaded json in dropdown / ng-options
On ng-change I also like to pass selected object's campaignType.
How would I able to do that?
My View is looking like this
<div ng-app>
<div ng-controller="cCtrl">
<select ng-model="campaign" ng-options="c.id as c.name for c in campaigns" ng-change="search2(c.campaignType)">
<option value="">-- choose campaign --</option>
</select>
</div>
</div>
My Controller is looking like this
function cCtrl($scope) {
$scope.campaigns = [{
"custID": 1,
"custName": "aaa ",
"msgID": 3,
"msgName": "Email Test Msg",
"id": 2,
"name": "Email Test Campaign",
"description": "Test Campaign",
"campaignType": "Email",
"created": "1374229715",
"isActive": 1,
"isDeleted": 0
}];
$scope.search2 = function (campaignType) {
alert(campaignType); // not working
alert($scope.campaign.campaignType); // not working
//console.log($scope.campaign.campaignType);
}
}
http://jsfiddle.net/webtheveloper/Qgmz7/8/
Instead of passing in a property, you can pass the selected object into the function like this
<select ng-model="campaign" ng-options="c.name for c in campaigns" ng-change="search2(campaign)">
Working Demo
Check this out: http://jsfiddle.net/Qgmz7/9/
You are not in an ngRepeat context. ngOptions works totally different.
ngModel on a <select> will get the value of the <option>, not the whole object. Again, you are not inside an ngRepeat, you don't have access to your objects.
No need to pass the value as parameter, you can get it from $scope. As a matter of fact you don't need ngChange either, you can just $scope.$watch('campaign', ...)
So
$scope.search2 = function () {
console.log($scope.campaign);
}
You can also try it this way (Hack we can say),
<select ng-model="campaign" ng-options="c.id as c.name for c in campaigns" ng-change="search2(campaign,campaigns)">
<option value="">-- choose campaign --</option>
</select>
Basically what this piece of code will do is that it will just pass ng-model along with the whole dropdown list to ng-change.
So in search2 Function, you can just search that ng-model value into that list and get your desired object.
Fiddle for reference : https://jsfiddle.net/vaibhavgavali92/7b7xdyzj/18/
In some cases such as just to display the member value corresponding item selected would not require a call to Controller function. For example if you want to display the campaign type corresponding to selected campaign, it can be written as follow.
<select ng-model="campaign" ng-options="c.name for c in campaigns">
...
<tr><td>Campaign Type:</td><td>{{campaign.campaignType}}</td></tr>
<tr><td>Campaign Description:</td><td>{{campaign.description}}</td></tr>

AngularJS: Select Element - Have a different model and a value for options

I have an javascript object as follows in my controller:
$scope.options = [
{
"actualValue": "age",
"displayValue": "Age"
},
{
"actualValue": "maiden",
"displayValue": "Maiden Name"
}
];
Now, I am displaying a select element in which the options of the element will be the values in the "displayValue" property written above:
<select ng-options="entry.displayValue for entry in options" ng-model="biodata">
<options>-- Select a BioData Option --</option>
</select>
Now, my problem is that the ng-model for the select element above when the user select a value from the dropdown is the "displayValue" property. I wish that the ng-model be the "actualValue" property.
How can I achieve this?
<select ng-options="entry.actualValue as entry.displayValue for entry in options"></select>
Fiddle: http://jsfiddle.net/rzV65/
Already answered here: How do I set the value property in AngularJS' ng-options?

Resources