Why does this empty <option> in ng-options clear all selections? - angularjs

I have a plunker here to demonstrate.
I am using a blank option tag in my ng-options select.
<select ng-model="food.fruitOne"
ng-options="fruit.id as fruit.name for fruit in fruits | filter: food.fruitTwo && {id: '!' + food.fruitTwo} | filter: food.fruitThree && {id: '!' + food.fruitThree}">
<option value="">-</option>
</select>
The select list is used 3 times for 3 different ng-models. Strangely, if you make a selection from any of the choices and then change that selection back to the blank option all 3 choices switch to the blank option and the selects all crap out.
Interesting. In this plunk which does not use the filters, the selects don't act that way. Clearly the filter is the culprit. Why?
Thanks!

This is error in yours filter in ng-repeat.
See updated plunker
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.food = {
fruitOne: "",
fruitTwo: "",
fruitThree: ""
};
$scope.fruits = [{
id: 1,
name: 'apple'
}, {
id: 2,
name: 'banana'
}, {
id: 3,
name: 'orange'
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="plunker" ng-controller="MainCtrl">
<label>Choice 1</label>
<select ng-model="food.fruitOne" ng-options="fruit.id as fruit.name for fruit in fruits | filter:food.fruitTwo!=''?{id: '!' + food.fruitTwo}:{} | filter:food.fruitThree!=''? {id: '!' + food.fruitThree}:{}">
<option value=""></option>
</select>
<label>Choice 2</label>
<select ng-model="food.fruitTwo" ng-options="fruit.id as fruit.name for fruit in fruits | filter: food.fruitOne!=''?{id: '!' + food.fruitOne}:{} | filter: food.fruitThree!=''?{id: '!' + food.fruitThree}:{}">
<option value=""></option>
</select>
<label>Choice 3</label>
<select ng-model="food.fruitThree" ng-options="fruit.id as fruit.name for fruit in fruits | filter: food.fruitOne!=''?{id: '!' + food.fruitOne}:{} | filter: food.fruitTwo!=''?{id: '!' + food.fruitTwo}:{}">
<option value=""></option>
</select>
<hr>
<p>Choice 1 - {{ food.fruitOne }}</p>
<p>Choice 2 - {{ food.fruitTwo }}</p>
<p>Choice 3 - {{ food.fruitThree }}</p>
</body>

ng-options and option does not work together.
You need to use only one of them. Both of them do not work together in the same directive.
The best way to add some particular values is to have it included in the model. For that you will need to customize your filter. That's how I did it in project.
Change your model to this:
$scope.fruits = [
{id: 4, name: ' '},
{id: 1, name: 'apple'},
{id: 2, name: 'banana'},
{id: 3, name: 'orange'}
];

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];

How to make ng-select work properly

I have this ng-select element:
<body ng-controller="MainCtrl">
<select ng-model="selectedItem" ng-model="selectedItem">
<option value="-1" selected>- manual -</option>
<option ng-repeat="(key, value) in items">{{value.Name}}</option>
</select>
</body>
Here is controller:
$scope.selectedItem = null;
$scope.items = [{Name: 'one', Id: 30 },
{Name: 'two', Id: 27 },
{Name: 'threex', Id: 50 }];
Here is working PLUNKER.
Inside of ng-select I have two options the static(-manual-) and the options generated by ng-repeat element.
My problem is: when user make selection of the option generated by ng-repeat the
$scop.selectedItem get the Name of the selected item, while I need to set the Id of the selected element.
For example:
If in the plunker above user select from ng-select element two the $scop.selectedItem will get two the name of the item while, I need $scop.selectedItem to get 27 the Id of the selected item.
Any idea how can I make $scop.selectedItem to get the Id of the selected item?
Have a look at the ng-options directive. You can pass a list comprehension like expression to extract what you need.
For example:
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
https://docs.angularjs.org/api/ng/directive/ngOptions
As Delapouite said, you should use ng-options. I've updated your plunkr to implement this.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.items = [{name: '- manual -', id: -1 },
{name: 'one', id: 30 },
{name: 'two', id: 27 },
{name: 'threex', id: 50 }];
$scope.selectedItem = $scope.items[0];
});
<select
ng-model="selectedItem"
ng-options="item.name for item in items track by item.id"
></select>
Try this
<option ng-repeat="(key, value) in items" key="{{value.Id}}" value="{{value.Id}}">{{value.Name}}</option>
All that I have done is I have set key and value = {{value.Id}} and the selectedItem will pick it up.
Here's the UPDATED PLNKR
I would suggest to use ng-options and to push your default value (manual) in $scope.items.
I used ng-init to set the default value of your select to - manual -.
<body ng-controller="MainCtrl">
<select ng-model="selectedItem" ng-options="i.Id as i.Name for i in items" ng-init="selectedItem = items[0].Id"></select>
selected item: {{selectedItem}}
</body>
$scope.items = [{Name:'- manual -', Id: -1},
{Name: 'one', Id: 30 },
{Name: 'two', Id: 27 },
{Name: 'threex', Id: 50 }];
Here is a working Plnkr.

Select dropdown not generated via ng-repeat and ng-options

The two dropdowns below doesnt generate an array of years. I also need the years to be sorted from earliest to latest but the orderBy filter isnt working.
<select title="- Select a period -" class="period " id="reportingPeriods">
<option ng-repeat="reportingPeriod for reportingPeriod in reportingPeriods">{{reportingPeriod}}</option>
</select>
<br />
<select title="- Select a period -" class="period selectpicker" id=""
ng-options="reportingPeriod for reportingPeriod in reportingPeriods | orderBy: '-reportingPeriod' ">
</select>
Here is my javascript
(function(angular) {
'use strict';
angular.module('ngrepeatSelect', [])
.controller('ExampleController', ['$scope', function($scope) {
console.clear();
$scope.data = {
repeatSelect: null,
availableOptions: [
{id: '1', name: 'Option A'},
{id: '2', name: 'Option B'},
{id: '3', name: 'Option C'}
],
};
$scope.reportingPeriods = [1999, 2011, 2000, 1988, 1995, 2014];
}]);
})(window.angular);
Here is my plunkr
You are using the wrong syntax for the ng-options and ng-repeat in the select options. Fixed here - http://plnkr.co/edit/oPI9kvQFuYJmrEwBDnWv?p=preview
Also you need to assign your ng-models to the select for them to work (as mentioned in the comments above by #AvijitGupta)
<select ng-model="period" title="- Select a period -" class="period " id="reportingPeriods">
<option ng-repeat="reportingPeriod in reportingPeriods">{{reportingPeriod}}</option>
</select>
<br />
<select ng-model="preiod" title="- Select a period -" class="period selectpicker" id=""
ng-options="reportingPeriod for reportingPeriod in reportingPeriods | orderBy: '-' ">
</select>

Filter multiple items based on array of values

I have a select box that is populated using ng-options.
$scope.items = [
{ID: '2012', Title: 'Chicago'},
{ID: '2013', Title: 'New York'},
{ID: '2014', Title: 'Washington'},
];
<select ng-model="selectedItem" ng-options="item.ID as item.Title for item in items | filter:filterItemNames">
</select>
This returns...
<option value="2012">Chicago</option>
<option value="2013">New York</option>
<option value="2014">Washington</option>
I would like to filter and display multiple items based on their name (i.e. New York and Chicago).
I'm currently trying to use an array with item names to filter, but this is not working.
$scope.filterItemNames = ['New York', 'Chicago'];
In this case you could create custom filter function:
$scope.filterByNames = function(el) {
return !$scope.filterItemNames || $scope.filterItemNames.indexOf(el.Title) > -1;
};
and use it like this in HTML:
<select ng-model="selectedItem"
ng-options="item.ID as item.Title for item in items | filter:filterByNames">
</select>
Demo: http://plnkr.co/edit/lqiMIlEYdrLlS6K0H2g9?p=preview

Resources