Angularjs compare two objects in ng-options - angularjs

I have two arrays of objects.
A very simplified example:
$scope.genres = [
{
id: '123',
name: 'Genre 1'
},
{
id: '124',
name: 'Genre 2'
},
{
id: '125',
name: 'Genre 3'
}
];
$scope.selectedGenres = [{
id: '123',
name: 'Genre 1'
}];
I use genres to populate a select.
<select style="height: 100px; width: 100%;"
multiple
ng-model="selectedGenres"
ng-options="option as option.name for option in genres"></select>
I realise doing: $scope.selectedGenres = [$scope.genres[0]];
Would work as the objects reference is the same.
Is there any way to compare the two objects for equality rather than their reference?
Example: http://jsbin.com/cizuyitadu/6/edit

In your example your objects don't have the same properties so they are not going to be equal when using angular.equals. Your selectedGenres object has a '$$hashKey' property on it (angular adds this) because you're not a specifying tracking property. The objects in your $scope.genres array don't have the '$$hashKey' property. That's why angular.equals is returning false.
If you add a track by property in your ng-options expression it will fix the issue.
ng-options="option as option.name for option in genres track by option.id"

Add the following to your ng-options "track by option.id"
<select style="height: 100px; width: 100%;"
multiple
ng-model="selectedGenres"
ng-options="option as option.name for option in genres track by option.id"></select>
That will automatically select that option. That works in your example, and I presume that is what you are trying to do?

angular.equals is probably what you're looking for:
https://docs.angularjs.org/api/ng/function/angular.equals

Related

AngularJS option length IE

I have option list of some types like car, bus in format like this: <option value="BUS" label="Bus">Bus</option> and when I want to count the length of the list I use angular.element(element[0].options).length in Chrome it returns the correct length, but on Internet Explorer it returns 1
Use element[0].options.length directly, instead of wrapping it in angular.element(). If your list is data driven (which I recommend) then you can also just check the length of your array that contains the data.
var list = document.getElementById('list');
console.log('list.options.length = ' + list.options.length);
<select id="list">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
Regarding the data driven list, ideally you should have an array of vehicles/transports/anything (might be complex objects with properties or just unique strings). Once you expose that array to the view (via scope or this from controllerAs syntax) then you can generate the list of options using ngOptions. For example:
Controller JS:
$scope.items = [{
id: 1,
label: 'aLabel',
subItem: { name: 'aSubItem' }
}, {
id: 2,
label: 'bLabel',
subItem: { name: 'bSubItem' }
}];
Template HTML:
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>

AngularJS: refresh ng-options when property source object changes

Full description:
I have list of options with multiple properties (not just key-value pair):
[
{
id: 1,
name: "111",
some: "qqq"
},
{
id: 2,
name: "222",
some: "www"
}
];
And select defined as:
<select name="mySelect" id="mySelect"
ng-options="option.name for option in opts track by option.id"
ng-model="mod1"></select>
Depending on app logic, extra property may change:
{
id: 2,
name: "222",
some: "www1"
}
But actual list in Select doesn't change!
However, if name changes, then entire optionList will be refreshed.
In short you can see demo on JSFiddle OR JSFiddle. I prepared 2 very similar examples:
When button is clicked only extra property updates
When button is clicked - both extra property and key receive new value
Does anybody know solution?
UPDATE
For now I'm solving that issue with update + delay + update solution:
this.click = function(){
$scope.opts = {};
$timeout(function() {
$scope.opts = { /* NEW OBJECT */};
}, 0);
}
OK, so I think I understand what you want, which is to be able to select an option whose nested values may have changed since the list was rendered in the DOM.
Based on that understanding, I believe that the plunker I have created illustrates a solution for you. If you select one of the options, and change the child value in the input field, two-way binding will update the model.
Basically, it is taking the users selection, and on select change, re-assigning the selected object to reference the original option in the options array. This will allow two-way binding to occur. If you view the code, you will see that the input fields are updating the option list itself ($scope.options), where-as the model that is being displayed is $scope.formData.model.
https://plnkr.co/edit/DLhI7t7XBw9EbIezBCjI?p=preview
HTML
<select
name="mySelect"
id="mySelect"
ng-model="formData.model"
ng-change="onChange(formData.model)"
ng-options="option.name for option in options track by option.id"></select>
SELECTED CHILD: {{formData.model.child.name}}
<hr>
<div ng-repeat="option in options">
Child Name for {{ option.name }}: <input ng-model="option.child.name">
</div>
JS
$scope.onChange = function(option) {
angular.forEach($scope.options,function(optionItem){
if (optionItem.id == option.id){
$scope.formData.model = optionItem;
}
})
}
$scope.options = [
{
id: 1,
name: "111",
child: {
id: 11,
name: "111-1"
}
},
{
id: 2,
name: "222",
child: {
id: 22,
name: "222-1"
}
}
];
$scope.formData = {
model: $scope.options[0]
};
Call $apply whenever you want to apply changes made.
$scope.$apply();
This will tell AngularJS to refresh.

how do i filter items by property in ng-options?

I have some data and a select control as you can see from my code sample below. It works for me but I want to be able to filter the data by type. In my code sample, I show one way I have tried to filter the data based on the type being a value of one. I am not sure if the way I am creating the select is causing this simple inline filter to not work or if I am doing something wrong?
$scope.data = [{
name : "5 play",
type : 1
}, {
name : "one on one",
type : 2}, {
name : "two on one",
type : 2}];
<select class="form-control" ng-model="selectedRule"
ng-options="item as (item.Name) for item in data track by item.Name | filter:{type:1}"></select>
As stated in angular docs, track by must always be the last expression:
Note: track by must always be the last expression
My guess is that all that follows is not considered, so that´s why your filter wasn´t applying. Moving the track by to the right place should fix it
Yes, as mentioned. Move the track by at the end and make the letter N lowercase like in the following demo or in this fiddle.
angular.module('demoApp', [])
.controller('mainController', MainController);
function MainController($scope) {
$scope.data = [{
name: "5 play",
type: 1
}, {
name: "one on one",
type: 2
}, {
name: "two on one",
type: 2
}];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController">
<select class="form-control" ng-model="selectedRule" ng-options="item as item.name for item in data | filter:{type:1} track by item.name"></select>
</div>

Setting default value in select drop-down using Angularjs

I have an object as below. I have to display this as a drop-down:
var list = [{id:4,name:"abc"},{id:600,name:"def"},{id:200,name:"xyz"}]
In my controller I have a variable that carries a value. This value decided which of the above three items in the array will be selected by default in the drop-down:
$scope.object.setDefault = 600;
When I create a drop-down form item as below:
<select ng-model="object.setDefault" ng-options="r.name for r in list">
I face two problems:
the list is generated as
<option value="0">abc</option>
<option value="1">def</option>
<option value="2">xyz</option>
instead of
<option value="4">abc</option>
<option value="600">def</option>
<option value="200">xyz</option>
No option gets selected by default even though i have ng-model="object.setDefault"
Problem 1:
The generated HTML you're getting is normal. Apparently it's a feature of Angular to be able to use any kind of object as value for a select. Angular does the mapping between the HTML option-value and the value in the ng-model.
Also see Umur's comment in this question: How do I set the value property in AngularJS' ng-options?
Problem 2:
Make sure you're using the following ng-options:
<select ng-model="object.item" ng-options="item.id as item.name for item in list" />
And put this in your controller to select a default value:
object.item = 4
When you use ng-options to populate a select list, it uses the entire object as the selected value, not just the single value you see in the select list. So in your case, you'd need to set
$scope.object.setDefault = {
id:600,
name:"def"
};
or
$scope.object.setDefault = $scope.selectItems[1];
I also recommend just outputting the value of $scope.object.setDefault in your template to see what I'm talking about getting selected.
<pre>{{object.setDefault}}</pre>
In View
<select ng-model="boxmodel"><option ng-repeat="lst in list" value="{{lst.id}}">{{lst.name}}</option></select>
JS:
In side controller
$scope.boxModel = 600;
You can do it with following code(track by),
<select ng-model="modelName" ng-options="data.name for data in list track by data.id" ></select>
This is an old question and you might have got the answer already.
My plnkr explains on my approach to accomplish selecting a default dropdown value. Basically, I have a service which would return the dropdown values [hard coded to test]. I was not able to select the value by default and almost spend a day and finally figured out that I should have set $scope.proofGroupId = "47"; instead of $scope.proofGroupId = 47; in the script.js file. It was my bad and I did not notice that I was setting an integer 47 instead of the string "47". I retained the plnkr as it is just in case if some one would like to see. Hopefully, this would help some one.
<select ng-init="somethingHere = options[0]" ng-model="somethingHere" ng-options="option.name for option in options"></select>
This would get you desired result Dude :) Cheers
Some of the scenarios, object.item would not be loaded or will be undefined.
Use ng-init
<select ng-init="object.item=2" ng-model="object.item"
ng-options="item.id as item.name for item in list"
$scope.item = {
"id": "3",
"name": "ALL",
};
$scope.CategoryLst = [
{ id: '1', name: 'MD' },
{ id: '2', name: 'CRNA' },
{ id: '3', name: 'ALL' }];
<select ng-model="item.id" ng-selected="3" ng-options="i.id as i.name for i in CategoryLst"></select>
we should use name value pair binding values into dropdown.see the
code for more details
function myCtrl($scope) {
$scope.statusTaskList = [
{ name: 'Open', value: '1' },
{ name: 'In Progress', value: '2' },
{ name: 'Complete', value: '3' },
{ name: 'Deleted', value: '4' },
];
$scope.atcStatusTasks = $scope.statusTaskList[0]; // 0 -> Open
}
<select ng-model="atcStatusTasks" ng-options="s.name for s in statusTaskList"></select>
I could help you out with the html:
<option value="">abc</option>
instead of
<option value="4">abc</option>
to set abc as the default value.

ngOptions ordering and selecting objects in array

I have a set of options in my controller that looks like this:
$scope.options = [
{one: 'ONE'},
{two: 'TWO'},
{three: 'THREE'}
];
My view looks like the following currently looks like this:
<div ng-repeat="goal in objectives">
...
<select ng-model="goal.choices" ng-options="value for (key, value) in options"> </select>
...
</div>
PROBLEM: the resulting dropdown is not sorted by obj occurence in array rather by alpha of each objects key AND there is no default option selected, i want the dropdown to default to 'one' not ''
What is the ng-options expression need to make this work?????
Thanks
Your $scope.options array isn't usable in ngOptions because you have an array of three entirely different objects (one has a one property, another a two property, and the last a three property). If you want the select to default to $scope.choices[0], then goal.choices needs to be set to $scope.options[0].
I had to make some guesses here, because you didn't include what $scope.objectives was, but I can imagine you were going for something like this:
http://jsfiddle.net/A5KkM/
HTML
<div ng-app ng-controller="x">
<div ng-repeat="goal in objectives">{{goal.choice}}
<select ng-model="goal.choice" ng-options="o.name for o in options"></select>
</div>
</div>
JavaScript
function x($scope) {
$scope.options = [{
name: 'ONE'
}, {
name: 'TWO'
}, {
name: 'THREE'
}];
$scope.objectives = [{ choice: $scope.options[0] }, { choice: $scope.options[1] }];
}

Resources