Duplicates in ngOptions - javascript

I am using AngularJS version 1.4.7 and have simple AngularJS controller which contains array of objects. I would like to display these objects as options in select by ngOptions.
The problem is that every object is duplicate and I don't know why. This duplicate is presented in the select only, the source object looks fine.
angular
.module('demo', [])
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl() {
var vm = this;
vm.demoOptions = [
{value: 1, label: 'Demo 1'},
{value: 2, label: 'Demo 2'},
{value: 3, label: 'Demo 3'}
];
vm.selected = null;;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoCtrl as vm">
<select ng-options="item as item.label for item in vm.demoOptions track by item.value" ng-model="vm.selected">
<option value="" selected ng-if="vm.selected === null">-- select --</option>
</select>
<p ng-if="vm.selected !== null">Selected item: <code>{{vm.selected}}</code></p>
<p ng-if="vm.selected === null">No item is selected.</p>
<pre>vm.demoOptions == {{vm.demoOptions|json}}</pre>
</div>
Is it a bug? How can I remove duplicates without using a filter?
Note: This problem has occurred after update AngularJS from version 1.3.19 to 1.4.7. I read the changelog but it tells only about addition of track by - I added it but with no effect.

It is a known bug for 1.4.x before 1.4.8 you can check issue.
If you have to use angularjs 1.4.7 version then you can use ng-show instead ng-if
You can find changelog and error from angularjs github

You have to remove your <option> tag from the <select> field. Since everything inside it will be used for every item and the <option> tag itself is generated through the directive of angularJS.
angular
.module('demo', [])
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl() {
var vm = this;
vm.demoOptions = [
{value: 1, label: 'Demo 1'},
{value: 2, label: 'Demo 2'},
{value: 3, label: 'Demo 3'}
];
vm.selected = null;;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoCtrl as vm">
<select ng-options="item as item.label for item in vm.demoOptions track by item.value" ng-model="vm.selected" ng-change="vm.setSelected()">
</select>
<p ng-if="vm.selected !== null">Selected item: <code>{{vm.selected}}</code></p>
<p ng-if="vm.selected === null">No item is selected.</p>
<pre>vm.demoOptions == {{vm.demoOptions|json}}</pre>
</div>

angular
.module('demo', [])
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl($scope) {
var vm = this;
vm.demoOptions = [
{value: null, label: '--select--'},
{value: 1, label: 'Demo 1'},
{value: 2, label: 'Demo 2'},
{value: 3, label: 'Demo 3'}
];
vm.selected = vm.demoOptions[0];
$scope.$watch(function(){ return vm.selected}, function(newVal, oldVal){
if(!oldVal.value && newVal.value) {
vm.demoOptions.shift();
}
});
vm.setSelected = function(){
}
}
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoCtrl as vm">
<select ng-options="item.label for item in vm.demoOptions" ng-model="vm.selected" ng-change="vm.setSelected()">
</select>
<p ng-if="vm.selected !== null">Selected item: <code>{{vm.selected}}</code></p>
<p ng-if="vm.selected === null">No item is selected.</p>
<pre>vm.demoOptions == {{vm.demoOptions|json}}</pre>
</div>

If you are experiencing this in 1.4.8 or greater the reason may be this bug. Duplicates can be created when using $compile. There are some workarounds on the bug page.

Related

Select does not keep the value chosen by user

I'm new on Angular, and i'm pretty stuck on a simple select problem.
i did a simple select which iterate my scope to populate the select, but after a user click on an option (which are well created), my select becomes blank with no selection inside, and if i click it again there are no options visible.
below is my code:
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.searchFilterDispatcher = {};
$scope.searchFilterDispatcher.distributionCode = [{
id: 1,
label: 'dist1'
}, {
id: 2,
label: 'dist2'
}];
});
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<select ng-model="searchFilterDispatcher.distributionCode"
ng-options="item as (item.label | uppercase) for item in
searchFilterDispatcher.distributionCode"
class="form-control"
id="distributionCode">
<option >{{'SELECT_A_VALUE' | translate}}</option>
</select>
Any hint?
You should change your ng-model like following. It works in snippet
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.searchFilterDispatcher = {};
$scope.searchFilterDispatcher.distributionCode = [{
id: 1,
label: 'dist1'
}, {
id: 2,
label: 'dist2'
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<select ng-model="val" ng-options="item as (item.label | uppercase) for item in searchFilterDispatcher.distributionCode" class="form-control" id="distributionCode">
</select>
</div>

convert ng-repeat to ng-option error

I have this following html code for select tags.
<option ng-repeat="option in AllData" value="{{item.Id}}" ng-selected="data.Symbol==item.Id">{{item.Symbol}}</option>
I want to convert this to ng-options. can someone please shed some light on this.
the value of AllData is as follows. It is an array of objects.
0:Object
Id: 1
Symbol: "GR"
1:Object
Id: 2
Symbol: "DR"
I tried something like this but was not successful.
ng-options="item as item .Symbol for item in AllData track by item.Id">
Try this
<select ng-options="option as option.Symbol for option in AllData">
</select>
when using ngOptions, you have to also bind ng-model with the initial value of select.
mention that since you used track by item.Id, the default value should at least contains property Id and meets the one of the items Id property.
refer the below sample:
angular.module("app", [])
.controller("myCtrl", function($scope) {
$scope.AllData = [{
0: Object,
Id: 1,
Symbol: "GR"
}, {
1: Object,
Id: 2,
Symbol: "DR"
}];
//$scope.data = $scope.AllData[0];
$scope.data = {
0: Object,
Id: 1,
Symbol: "GR"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<select ng-model="data" ng-options="item as item.Symbol for item in AllData track by item.Id"></select> {{selectedItem}}
</div>

Angular equivalent of index() from jquery

I use Angular 1.5. I have two selects and I need to update 2nd select depending on the index of the option of 1st select.
Is there an easy way to get the index of option selected? Like from 0 to 5.
My 1st select is :
<select class="form-control" name="idEtablissement" ng-model="infosEtab.idEtablissement" ng-change="updateContrats()"
ng-options='item.id as item.name for item in listeEtablissement'>
</select>
I need something like that :
// return -1, listeEtablissement is [{id: 2, name: 'Test'}, {...}]
alert($scope.listeEtablissement.indexOf($scope.infosEtab.id));
$listeEtablissement is :
[{id: 2, name: 'Test'}, {id: 5, name: 'Test 2'}]
But I need to have the index, like 0 or 1.
EDITED
Ok I'll use Javascript approach, the most simple one :
$scope.updateContrats = function() {
var index = document.getElementById('idEtablissement').selectedIndex;
// ....
}
You should do it by native JavaScript using array.findIndex(); like in this runnable demo fiddle.
MDN reference of array.findindex()
View
<div ng-controller="MyCtrl">
<select class="form-control"
name="idEtablissement"
ng-model="infosEtab.idEtablissement"
ng-change="updateContrats()"
ng-options='item.id as item.name for item in listeEtablissement'>
</select>
</div>
AngularJS Application
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.selectedIndex = null;
$scope.listeEtablissement = [{
id: 2,
name: 'Test'
}, {
id: 5,
name: 'Test 2'
}];
$scope.updateContrats = function() {
$scope.selectedIndex = $scope.listeEtablissement.findIndex(function(item) {
return item.id === $scope.infosEtab.idEtablissement
});
}
});
Change
ng-options
to
index as item.name for (index, item) in listeEtablissement

why isn't my angular options track by id working

I'm sure I must be doing this wrong, but:
I have an object that stores the id of an item. I also have an array of these items. I need to have a 'select' that represents the currently selected item, but that can also change the selected item.
I have set the 'select's model to the object.selectId.
The 'select' ng-options is "option.Text for option in options track by optionId"
Yet the model and 'select' options types don't match
How do I achieve what I need?
Here's a fiddle of what I am doing: https://jsfiddle.net/vb2xe1mc/5/
Code:
<script>
angular.module('myApp', [])
.controller('myctrl', ['$scope', function($scope) {
$scope.item = {
id: 1
};
$scope.options = [
{Text: "zero", Id: 0},
{Text: "one", Id: 1},
{Text: "two", Id: 2},
{Text: "three", Id: 3}
];
$scope.selectChange = function() {
alert($scope.item.id);
};
}]);
</script>
<div ng-app="myApp">
<div ng-controller="myctrl">
<select ng-model="item.id" ng-options="option.Text for option in options track by option.Id" ng-change='selectChange()'>
</select>
</div>
</div>
If you can, please let me know where I have gone wrong or correct the fiddle.
Thanks ^_^
Andy
Clarification:
The model item has id 1 already selected. I need the list to preselect the option with id 1 in this case. Also, When the option is selected it does not set the item.id to an int, rather it sets it to the entire option item. I need it to set the item.id to the option.Id
<select ng-model="item.id" ng-options="option.id as option.Text for option in options" ng-change='selectChange()'>
You want to select option.id, not option and track by is unnecessary.
Bind the select to ng-model="item", not ng-model="item.id".
Also decide on id vs. Id
<div ng-app="myApp">
<div ng-controller="myctrl">
<select ng-model="item" ng-options="option.Text for option in options track by option.Id" ng-change='selectChange()'>
</select>
</div>
</div>
angular.module('myApp', [])
.controller('myctrl', ['$scope', function($scope) {
$scope.item = {
Id: 1
};
$scope.options = [{
Text: "zero",
Id: 0
}, {
Text: "one",
Id: 1
}, {
Text: "two",
Id: 2
}, {
Text: "three",
Id: 3
}, ];
$scope.selectChange = function() {
console.log ($scope.item.Id)
alert($scope.item.Id);
};
}]);
See here for a fixed version: https://jsfiddle.net/ax3k418p/
https://jsfiddle.net/vb2xe1mc/10/
You need to bind item to ng-model, and inititally $scope.Id should be set to 1 not $scope.id = 1
Also check when you alert it should be alert($scope.item.Id);
<div ng-app="myApp">
<div ng-controller="myctrl">
<select ng-model="item" ng-options="option.Text for option in options" ng-change='selectChange()'>
</select>
</div>
</div>
JS:
angular.module('myApp', [])
.controller('myctrl', ['$scope', function($scope) {
$scope.item = {
Id: 1
};
$scope.options = [{
Text: "zero",
Id: 0
}, {
Text: "one",
Id: 1
}, {
Text: "two",
Id: 2
}, {
Text: "three",
Id: 3
}, ];
$scope.selectChange = function() {
alert($scope.item.Id);
};
}]);

AngularJs - ng-model in a SELECT

JSfiddle
Problem:
I have a SELECT-element in my page, which is filled in with an ng-repeat. It also has a ng-model which has a default value.
When I change the value, the ng-model adapts, that's ok. But the dropdown-list shows an empty slot at launch, where it should have the item with the default value selected instead.
Code
<div ng-app ng-controller="myCtrl">
<select class="form-control" ng-change="unitChanged()" ng-model="data.unit">
<option ng-repeat="item in units" ng-value="item.id">{{item.label}}</option>
</select>
</div>
With JS:
function myCtrl ($scope) {
$scope.units = [
{'id': 10, 'label': 'test1'},
{'id': 27, 'label': 'test2'},
{'id': 39, 'label': 'test3'},
]
$scope.data = {
'id': 1,
'unit': 27
}
};
You can use the ng-selected directive on the option elements. It takes expression that if truthy will set the selected property.
In this case:
<option ng-selected="data.unit == item.id"
ng-repeat="item in units"
ng-value="item.id">{{item.label}}</option>
Demo
angular.module("app",[]).controller("myCtrl",function($scope) {
$scope.units = [
{'id': 10, 'label': 'test1'},
{'id': 27, 'label': 'test2'},
{'id': 39, 'label': 'test3'},
]
$scope.data = {
'id': 1,
'unit': 27
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<select class="form-control" ng-change="unitChanged()" ng-model="data.unit">
<option ng-selected="data.unit == item.id" ng-repeat="item in units" ng-value="item.id">{{item.label}}</option>
</select>
</div>
try the following code :
In your controller :
function myCtrl ($scope) {
$scope.units = [
{'id': 10, 'label': 'test1'},
{'id': 27, 'label': 'test2'},
{'id': 39, 'label': 'test3'},
];
$scope.data= $scope.units[0]; // Set by default the value "test1"
};
In your page :
<select ng-model="data" ng-options="opt as opt.label for opt in units ">
</select>
Working Fiddle
You dont need to define option tags, you can do this using the ngOptions directive: https://docs.angularjs.org/api/ng/directive/ngOptions
<select class="form-control" ng-change="unitChanged()" ng-model="data.unit" ng-options="unit.id as unit.label for unit in units"></select>
However, ngOptions provides some benefits such as reducing memory and increasing speed by not creating a new scope for each repeated instance. angular docs
Alternative solution is use ng-init directive. You can specify function that will be initialize your default data.
$scope.init = function(){
angular.forEach($scope.units, function(item){
if(item.id === $scope.data.unit){
$scope.data.unit = item;
}
});
}
See jsfiddle
You can also put the item with the default value selected out of the ng-repeat like follow :
<div ng-app="app" ng-controller="myCtrl">
<select class="form-control" ng-change="unitChanged()" ng-model="data.unit">
<option value="yourDefaultValue">Default one</option>
<option ng-selected="data.unit == item.id" ng-repeat="item in units" ng-value="item.id">{{item.label}}</option>
</select>
</div>
and don't forget the value atribute if you leave it blank you will have the same issue.
Select's default value should be one of its value in the list. In order to load the select with default value you can use ng-options. A scope variable need to be set in the controller and that variable is assigned as ng-model in HTML's select tag.
View this plunker for any references:
http://embed.plnkr.co/hQiYqaQXrtpxQ96gcZhq/preview

Categories

Resources