3

I have an ui-select which is wrapped in ng-repeat directive. Since they share the same scope I have several problems:

  • after selecting value in first select second select is already prefilled with what I typed in first.

  • placeholder is hidden and shows only when select field is in focus.

Here is the html:

<div ng-repeat="repeat in repeats">
  <p>Selected: {{repeat.id.formatted_address}}</p>
  <ui-select ng-model="repeat.id"
             theme="bootstrap"
             ng-disabled="disabled"
             reset-search-input="false"
             style="width: 300px;">
    <ui-select-match placeholder="Enter an address...">{{$select.selected.formatted_address}}</ui-select-match>
    <ui-select-choices repeat="address in addresses track by $index"
                       refresh="refreshAddresses($select.search)"
                       refresh-delay="0">
      <div ng-bind-html="address.formatted_address | highlight: $select.search"></div>
    </ui-select-choices>
  </ui-select>
</div>

The question is what is the proper way to use several ui-select directives to prevent those issues?

Demo Plunker

streetturtle
  • 5,472
  • 2
  • 25
  • 43

2 Answers2

2

You can create a directive for the address lookup and move your lookup logic into the directive controller. Each directive instance will have its own controller instance and therefore its own instance of $scope.addresses (preventing the behaviour of pre-populating the second select as well as the first).

<div ng-repeat="repeat in repeats">
  <address-selector repeat="repeat"></address-selector>
</div>

app.directive('addressSelector', function() {
  return {
    restrict: 'E',
    scope: {
      repeat: '='
    },
    template:
    '<p>Selected: {{repeat.id.formatted_address}}</p>' +
    '<ui-select ng-model="repeat.id"' +
    '    theme="bootstrap"' +
    '    ng-disabled="disabled"' +
    '    reset-search-input="false"' +
    '    style="width: 300px;">' +
    '<ui-select-match placeholder="Enter an address...">{{$select.selected.formatted_address}}</ui-select-match>' +
    '<ui-select-choices repeat="address in addresses track by $index"' +
    '    refresh="refreshAddresses($select.search)"' +
    '    refresh-delay="0">' +
    '  <div ng-bind-html="address.formatted_address | highlight: $select.search"></div>' +
    '</ui-select-choices>' +
    '</ui-select>',
    controller: function ($scope, $http) {
      $scope.refreshAddresses = function(address) {
        var params = {address: address, sensor: false};
        return $http.get(
          'http://maps.googleapis.com/maps/api/geocode/json',
          {params: params}
        ).then(function(response) {
          $scope.addresses = response.data.results
        });
      };
    }
  };
}); 

For the ui-select placeholder to appear, you should avoid initialising the model (repeat.id), or set it to null.

app.controller('DemoCtrl', function($scope) {
  $scope.repeats=[{}, {}];
});

Updated Plunker

sheilak
  • 5,833
  • 7
  • 34
  • 43
0

You can also do something like this. Each object in the array will have its own selected item. To add new repeats you simply $scope.repeats.push({}) and to delete repeats do $scope.repeats.splice(index, 1);. If you want to push $scope.repeats to an API, remember to use angular.toJson($scope.repeats) instead of JSON.stringify($scope.repeats).

Of cause selected sub item is not needed if you only have that data. I had more items so this was useful for me

file.js

$scope.repeats=[{}, {}];

file.html

<div ng-repeat="repeat in repeats">
  <p>Selected: {{repeat.selected.formatted_address}}</p>
  <ui-select ng-model="repeat.selected">
    <ui-select-match placeholder="Enter an address...">
      {{$select.selected.formatted_address}}
    </ui-select-match>
    <ui-select-choices repeat="address in addresses track by $index">
      <div ng-bind-html="address.formatted_address | highlight: $select.search"></div>
    </ui-select-choices>
  </ui-select>
</div>

Output data might look like this:

$scope.repeats == [
    {
        selected: {
            formatted_address: "98 Hubin Middle Rd"
        }
    },
    {
        selected: {
            formatted_address: "100 Rogwart Way"
        }
    }
];
dǝɥɔS ʇoıןןƎ
  • 1,674
  • 5
  • 19
  • 42