Search code examples
angularjsangularjs-ng-repeatui-select

How to use properly ui-select in ng-repeat directive


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


Solution

  • 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