Angular ng-options track by issue - angularjs

I have a data set of objects that I'm displaying using ng-options. I'm binding the objects ID value to the value using track by
Currently, the data values are being included but they're being displayed with commas. For example...
$scope.items = [
{ID: '2012', Title: 'Chicago'},
{ID: '2013', Title: 'New York'},
{ID: '2014', Title: 'Washington'},
];
<select ng-options="item.Title for item in items track by item.ID">
</select>
But this will render...
<option value="2,0,1,2" label="Chicago">Chicago</option>
<option value="2,0,1,3" label="New York">New York</option>
Why are these commas being added, and how can I remove them?

You don't need track by:
<select ng-options="i.ID as i.Title for i in items" ng-model="someModel"></select>
After rendering you will have:
<option value="2012">Chicago</option>
<option value="2013">New York</option>

Your way
<select ng-options="item.ID as item.Title for item in items" ng-model="someModel"></select>
Fiddle
Alternate way
<select ng-model="selectedItem">
<option ng-repeat="item in items" value="{{item.ID}}">{{item.Title}}</option>
</select>
Fiddle2

You want:
<select ng-options="obj.ID as obj.title for obj in items"></select>
Track by just helps angular internally with array sorting. See: stack overflow answer

Try this:
<select ng-model="selectedItemID" ng-options="item.ID as item.Title for item in items">
</select>
Selected ID: {{selectedItemID}}

function MyController($scope){
$scope.items = [
{ID: '2012', Title: 'Chicago'},
{ID: '2013', Title: 'New York'},
{ID: '2014', Title: 'Washington'},
];
};
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-controller="MyController">
<select ng-model="selectedItem" ng-options="item.ID as item.Title for item in items track by item.ID"></select>
<br/>{{selectedItem}}
</body>
</html>
Following should work:--
<select ng-model="selectedItem" ng-options="item.ID as item.Title for item in items track by item.ID"></select>
{{selectedItem}}

If you want it to be by id then you should use
item.id as item.name for item in items

Related

What are the Angular ways to generate <option> elements that requires value and text dynamically from data for <select>?

I want to generate an option list using angular expression to achieve
<select id="sel">
<option value="1">value1</option>
<option value="2">value2</option>
<option value="3">value3</option>
</select>
on selection of which it will return an object or a simple value.
I have data from the server that resembles
this
["string1", "string2", "string3"]
and sometimes this
[
{val: '01', Text: 'struct1'},
{val: '02', Text: 'struct2'},
{val: '03', Text: 'struct3'}
]
and sometimes
[
{id: '01', obj: {grp: 'A', Text: 'struct1'}},
{id: '02', obj: {grp: 'A', Text: 'struct2'}},
{id: '03', obj: {grp: 'A', Text: 'struct3'}}
];
To accomplish the smooth transformation from data objects to a list of selectable objects (options) with one line code, we need to understand how angularJS structure their template!! Here is how ==>
XXX as YYY for ZZZ in ZZZZ
XXX is your final value that you pick from the options
YYY is your value text of your value
ZZZ is one item of your ZZZZ items
From above you can derive various flavors of result from the user's on click on selection. The entire code is like that
HTML==>
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<pre>itm for itm in stringArray : Result==> {{L1}}</pre>
<select ng-model="L1" ng-options="itm for itm in stringArray">
<option value="">the strings</option>
</select>
<hr/>
<pre>itm as itm.Text for itm in structArray : Result==> {{L2}}</pre>
<select ng-model="L2" ng-options="itm as itm.Text for itm in structArray">
<option value="">the structs</option>
</select>
<hr/>
<pre>itm.val as itm.Text for itm in structArray : Result==> {{L3}}</pre>
<select ng-model="L3" ng-options="itm.val as itm.Text for itm in structArray">
<option value="">the structs</option>
</select>
<hr/>
<pre>itm as itm.Text for itm in structArray track by itm.val : Result==> {{L4 | json}} </pre>
<select ng-model="L4" ng-options="itm as itm.Text for itm in structArray track by itm.val">
<option value="">the structs</option>
</select>
<hr/>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.stringArray = ["string1", "string2", "string3"];
$scope.structArray =
[
{val: '01', Text: 'struct1'},
{val: '02', Text: 'struct2'},
{val: '03', Text: 'struct3'},
];
});
</script>
</body>
</html>
Notice that I have also inserted a blank option inside the option list after the deploy of objects from that in-line template statement!
Notice that, you can return json object from the select change event. That means, you can expect an object picked by the user from selecting an option inside the list which is very powerful!

AngularJS ng-options ng-model option selected by id

Why this code doesn't work as expected? I expect China be selected in the select but it is empty.
<div ng-app="app">
<div ng-controller="appController" class="p-2" ng-init="init()">
<select
name="user_country"
class="form-control"
ng-model="country"
ng-options="item.id as item.title for item in countries track by item.id">
<option value="" disabled>Select Country</option>
</select>
</div>
</div>
Controller:
var app = angular.module('app', []).controller('appController', ['$scope', function($scope){
$scope.country = 3
$scope.countries = [
{id: 1, title: 'US'},
{id: 2, title: 'Japan'},
{id: 3, title: 'China'},
{id: 4, title: 'Russia'}
]
}])
I expect to see China rather than an empty field. Here is a CodePen example https://codepen.io/grinev/pen/YJERvz.
Udpated the ng-options to
ng-options="item.id as item.title for item in countries">
Answer
without track By - JSFiddle
with track By - JSFiddle
track by just helps Angular internally with array sorting as far as I know. The value of the options is defined by the first argument (in your case item). If you want it to be by id then you should use item.id as item.name for item in items
You need to be storing the object, not the id. So instead of $scope.country = 3; you need to put it after the countries array and set it to $scope.country = $scope.countries[2];

Angularjs select not passing value

I have a select dropdown in a form, it's not passing value to {{service}} object:
<select name="categoryId" ng-model="service.categoryId" ng-options="category.id as category.name for category in categories track by category.categoryId" required>
<option value="0">-select a category-</option>
</select>
And I can't find a reason why, anyone?
Check this example, it may help you:
function theController($scope) {
$scope.categories = [
{name:'First', id:'A', categoryId: 1},
{name:'Second', id:'B', categoryId: 2},
{name:'Third', id:'C', categoryId: 3}
];
$scope.service = $scope.categories[1];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<body ng-app>
<div ng-controller="theController">
<select name="categoryId"
ng-model="service"
ng-options="category as category.name for category in categories track by category.categoryId" required>
<option value="">-select a category-</option>
</select>
<pre>categories = {{categories|json}}</pre>
<pre>service = {{service|json}}</pre>
</div>
</body>

Angular: Drop Down Item active based on model dependency

I'd like the active state of items in one drop-down list to be contingent on properties from a second model:
angular.module('mainApp')
.controller('MainCtrl', function($scope) {
$scope.departments = [
{id:0, name: 'Dry Goods'},
{id: 1, name:'Frozen Food'},
{id: 2, name:'Electronics'}
];
$scope.categories = [
{id: 0, name: 'cereal', departmentId: 0},
{id: 1, name: 'cookies', departmentId: 0},
{id: 2, name: 'televisions', departmentId: 2}
];
});
and the drop-downs:
<select ng-model="department" ng-options="department.name for department in departments" ng-change="changeDepartment()">
<option value="">Department</option>
</select>
<select ng-model="category" ng-options="category.name for category in categories" ng-change="changeCategory()">
<option value="">Category</option>
</select>
I'd like the Department drop-down to display all three items, but only 'Dry goods' and 'Electronics' should be selectable because there are items in Category that map to Department through the departmentId property. Frozen food should be grayed out.
Plunker : http://plnkr.co/edit/c7rZ05qqRCnB7L0ANgZ4?p=preview
Thanks in advance.
Just use the $filter 'filter' in your second select, fike this:
<select ng-model="category" ng-options="category.name for category in categories|filter:{departmentId:department.id}" ng-change="changeCategory()">
<option value="">Category</option>
</select>
Example
UPDATE
Since ng-options doesn't provide a functionality for indicating which values should be disabled, you only have 2 options:
Create a custom directive that will give you that option, this is not an easy task because that directive should be watching for the collection of the ng-select and the collection or selected value of the other select, in other words this: ng-options with disabled rows won't work for you.
Build your select with an ng-repeat, much easier, like this:
.
<div ng-controller='MainCtrl'>
<div class="btn-group">
<select ng-model="departmentID" ng-change="changeDepartment()">
<option value="">Category</option>
<option ng-repeat="department in departments" value="{{department.id}}" ng-disabled="(categories|filter:{departmentId:department.id}).length==0">{{department.name}}</option>
</select>
</div>
<div class="btn-group">
<select ng-model="categoryID" ng-change="changeCategory()">
<option value="">Category</option>
<option ng-repeat="category in categories" value="{{category.id}}" ng-disabled="departmentID!=category.departmentId">{{category.name}}</option>
</select>
</div>
</div>
Example

How to get option text value using AngularJS?

I'm trying to get a text value of an option list using AngularJS
Here is my code snippet
<div class="container-fluid">
Sort by:
<select ng-model="productList">
<option value="prod_1">Product 1</option>
<option value="prod_2">Product 2</option>
</select>
</div>
<p>Ordered by: {{productList}}</p>
{{productList}} returns the value of the option, eg: prod_1. I'm trying to get the text value 'Product 1'. Is there a way to do this?
The best way is to use the ng-options directive on the select element.
Controller
function Ctrl($scope) {
// sort options
$scope.products = [{
value: 'prod_1',
label: 'Product 1'
}, {
value: 'prod_2',
label: 'Product 2'
}];
}
HTML
<select ng-model="selected_product"
ng-options="product as product.label for product in products">
</select>
This will bind the selected product object to the ng-model property - selected_product. After that you can use this:
<p>Ordered by: {{selected_product.label}}</p>
jsFiddle: http://jsfiddle.net/bmleite/2qfSB/
Instead of ng-options="product as product.label for product in products"> in the select element, you can even use this:
<option ng-repeat="product in products" value="{{product.label}}">{{product.label}}
which works just fine as well.
Also you can do like this:
<select class="form-control postType" ng-model="selectedProd">
<option ng-repeat="product in productList" value="{{product}}">{{product.name}}</option>
</select>
where "selectedProd" will be selected product.
<div ng-controller="ExampleController">
<form name="myForm">
<label for="repeatSelect"> Repeat select: </label>
<select name="repeatSelect" id="repeatSelect" ng-model="data.model">
<option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
</select>
</form>
<hr>
<tt>model = {{data.model}}</tt><br/>
</div>
AngularJS:
angular.module('ngrepeatSelect', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.data = {
model: null,
availableOptions: [
{id: '1', name: 'Option A'},
{id: '2', name: 'Option B'},
{id: '3', name: 'Option C'}
]
};
}]);
taken from AngularJS docs

Resources