AngularJS dropdown not showing selected value

All we need is an easy explanation of the problem, so here it is.

Am facing problem in displaying selected value in angular dropdown.
it works when i give like this

$scope.selectedItem = $scope.items[1];

not working, if i give directly that value

$scope.selectedItem = { name: 'two', age: 27 };

HTML:

<html ng-app="app">
  <body>
    <div ng-controller="Test">
      <select ng-model="selectedItem" ng-options="item.name for item in items">
      </select>
    </div>
  </body>
</html>

JS:

var app = angular.module('app',[]);
app.controller('Test',function($scope){
   $scope.items = [{name: 'one', age: 30 },{ name: 'two', age: 27 },{ name: 'three', age: 50 }];
  $scope.selectedItem = $scope.items[1];
});

CODEPEN:
http://codepen.io/anon/pen/zxXpmR

SOLUTION:

Thank you samir-das. I fixed as per your suggestion.

var choosen_value = { name: 'two', age: 27 };
angular.forEach($scope.items, function(item){
  if(angular.equals(choosen_value, item)){
    $scope.selectedItem = item;
  }
});

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

As explained in the other answers, while the two objects may have the same properties and values, they are two different objects so angular doesn’t consider them to be equal.

You can however use the track by expression in ng-options to specify a property which will decide equality:

ng-options="item.name for item in items track by item.name"

http://codepen.io/anon/pen/WbWMrp

Method 2

Well, because

$scope.items[1] and { name: 'two', age: 27 } is totally different thing.

{ name: 'two', age: 27 } is a totally different object whereas $scope.items[1] is part of the object $scope.items

When you put something in the template using {{}}, angular add it in its watcher list.

SO when angular put it in the watch list, it was an object (i.e. { name: 'two', age: 27 } ) that is different than $scope.items.

selectedItem is attached with the object that you set in the controller. In summary while dirty checking, angular will checks selectedItem against { name: 'two', age: 27 } NOT against $scope.items

Hope you understand what I mean

Method 3

This is not an Angular feature/issue, it is a consequence of how object equality works in Javascript. This article does a fairly good job in explaining what is going on in a pretty concise way and gives some examples. Check out the source of lodash’s isEqual method (it will take you to the definition of baseIsEqualDeep eventually) to see how what you are trying to achieve can be done in pure JS.

In any case, I do not think there is an easy way to achieve this in Angular, you would have to re-write the way ng-options works and you probably do not want to go there…

Method 4

In angular, Arrays and objects are passed by reference while strings, numbers and booleans are passed by value. So, angular interprets $scope.items[1] and { name: 'two', age: 27 } as two different objects. That’s why your binding fails when you do $scope.selectedItem = { name: 'two', age: 27 }; directly and find it in ‘$scope.items’.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply