angular-ui/ui-select: how to set initial selected object correctly

sports picture sports · Nov 24, 2014 · Viewed 10.3k times · Source

This is my ui select in the view:

<ui-select ng-model="selectedLabel.selected" ng-disabled="fetchingLabels || working">
    <ui-select-match placeholder="">{{$select.selected.code}}</ui-select-match>
    <ui-select-choices repeat="label in labels| filterBy: ['name', 'code']: $select.search"> 
        <div ng-bind-html="label.code | highlight: $select.search"></div>
        <small ng-bind-html="label.name | highlight: $select.search"></small>
    </ui-select-choices>
</ui-select>

And this is the relevant code in my controller:

$scope.labels = [];
$scope.selectedLabel = {};
$scope.selectedLabel.selected = $scope.passedLabel; // This is an object passed 
                                                    // from the previous controller.
                                                    // The scope comes with it.


$scope.fetchLabels(); // This fetches the labels from the server
                      // and puts them in $scope.labels

The labels brought from the server are theoretically like these:

[{'labelId': 20, 'code': 'L20', 'name': 'some label'},
 {'labelId': 21, 'code': 'L21', 'name': 'other label'}, ...]

And the passed from-outside label, 'passedLabel', is theoretically like ONE of those in $scope.labels too, eg:

  passedLabel = {'labelId': 21, 'code': 'L21', 'name': 'other label'}


...I say theoretically because, empirically, I'm seeing that they are different because of the things that angular adds to them (eg. $$hashKey, or __proto__).

So, because of that difference, the $scope.selectedLabel.selected = $scope.passedLabel isn't matching the corresponding item in the ui-select (they are not the same object), and thus, the result of that is this behavior:

ui-select behavior with initial selection

How can I set the initial selection correctly? is there a way I can use id's instead of object comparisson? I want to avoid having a for like this:

  for (i=0; i<$scope.labels; i++) {
      if ($scope.labels[i].labelId == $scope.passedLabel.labelId) {
           $scope.selectedLabel.selected = $scope.labels[i]
      }
  }

which I'm pretty sure it would work as expected, but I would have to call that for after the ajax has returned... and I have other ui-selects too

Answer

Aditya Sethi picture Aditya Sethi · Nov 24, 2014

If you want to achieve the state that you have mentioned, then simply pass the correct reference to your model.

So after the success of the fetchlabel call you set the values in labels. Now in the success of this function you need to call the function that fetches presentLabel.

As soon as you get the data of present label you can get the index of that object in the labels scope.

var idx;
_.find($scope.labels, function(label, labelIdx){ 
  if(label.labelId == parentLabel.labelId){ idx = labelIdx; return true;}; 
});

$scope.selectedLabel = {};
$scope.selectedLabel.selected = $scope.labels[idx];

This will solve your purpose.