2014-10-23 3 views
0

Я пытаюсь создать угловую директиву, которая является оболочкой поверх директивы ui-select. Моя цель - предоставить директиве список с элементами и моделью, которая будет синхронизироваться с определенным свойством выбранного элемента (ов). Моя директива имеет 5 атрибутов:Как создать угловую директиву ui-select, которая связывает свойство выбранного элемента с моделью

 
ng-model - to specify the model, 
items - to specify the list of items, 
display-prop - the name of the property which will be used inside ui-select for display purpose, 
value-prop - the name of the property which will be used for model assignment, 
multiple [optional] - if multiple selection is allowed 

В директиве рамки ребенка у меня есть объект, который синхронизируется с Ui-выберите нг-моделью и при его изменении я обновляя основной объем.

Мне удается сделать все, что работает для одного выбранного элемента, и для нескольких элементов, когда вы начинаете с пустого выбора. Однако у меня все еще есть проблема с отображением начальных выбранных элементов, когда выбран множественный выбор. Я думаю, что проблема где-то с областями и методами $ watch между моей директивой и директивой ui-select. Похоже, что обновления в моей области директивы не влияют на u-select ng-model в случае массива.
Я создал Plunker с простым приложением, содержащим директиву и тестовый пример, где вы можете видеть, что один отбор работает правильно, но когда у меня есть массив, список не инициализируется.

angular.module('dgUi', ['ui.select', 'ngSanitize']) 

    .config(['uiSelectConfig', function(uiSelectConfig){ 
    uiSelectConfig.theme = 'select2'; 
    }]) 

    .controller('UiSelectWrapperConttoller', ['$scope', function($scope){ 
    $scope.userAddresses = [ 
     { 
     address: 'Address 1', 
     description: 'Home address' 
     }, 
     { 
     address: 'Address 2', 
     description: 'Office address' 
     }, 
     { 
     address: 'Address 3', 
     description: 'Test address 3' 
     }, 
     { 
     address: 'Address 4', 
     description: 'Test address 4' 
     } 
    ]; 

    $scope.currentUser = { 
     name: 'User 1', 
     address: 'Address 1' 
    }; 

    $scope.currentUser = { 
     name: 'User 1', 
     address: 'Address 2', 
     availableAddresses:['Address 3'] 
    }; 
    }]) 

    .directive('dgSelect', ['$parse', function ($parse) { 
     return { 
      restrict: 'AE', 
      require: ['ngModel'], 
      scope: true, 
      templateUrl: function(tElement, tAttrs) { 
       return '/global/dg-ui/dg-select' + ((angular.isDefined(tAttrs.multiple) ? '-multi' : '') + '.tpl.html'); 
      }, 
      compile: function (tElement, tAttrs) { 
       var displayPropSufix = tAttrs.displayProp ? '.' + tAttrs.displayProp : ''; 
       var isMultiple = angular.isDefined(tAttrs.multiple) ; 

       //match element config 
       if (tAttrs.placeholder) { 
        $('ui-select-match, *[ui-select-match]', tElement).attr('placeholder', tAttrs.placeholder); 
       } 

       if(isMultiple){ 
        $('ui-select-match, *[ui-select-match]', tElement).html('{{$item' + displayPropSufix + '}}'); 
       }else{ 
        $('ui-select-match, *[ui-select-match]', tElement).html('{{$select.selected' + displayPropSufix + '}}'); 
       } 


       //choices element config 
       $('ui-select-choices, *[ui-select-choices]', tElement).attr('repeat', 'listItem in ' + tAttrs.items + ' | filter:$select.search') 
       $('ui-select-choices, *[ui-select-choices]', tElement).html('<div ng-bind-html="listItem' + displayPropSufix + ' | highlight: $select.search"></div>'); 
       return function link(scope, element, attrs, ctrls) { 
        scope.ngModel = ctrls[0]; 
        scope.isMultiple = angular.isDefined(attrs.multiple) 
        scope.itemsGetter = $parse(attrs.items); 
        if(angular.isDefined(attrs.valueProp) && attrs.valueProp !== ''){ 
         scope.valuePropGetter = $parse(attrs.valueProp); 
        } 

        scope.getValueMapper = function(itemObject){ 
         return scope.valuePropGetter ? scope.valuePropGetter(itemObject) : itemObject; 
        } 


        scope.updateValueFromModel = function(modelValue){ 
         if(scope.isMultiple){ 
          var selectionArray = []; 
          angular.forEach(modelValue, function(modelItem, key){ 
           var modelItemValue = scope.getValueMapper(modelItem); 
           selectionArray.push(modelItemValue); 
          }); 
          scope.selectionModel = selectionArray; 
         }else{ 
          var items = scope.itemsGetter(scope); 
          angular.forEach(items, function(item, key){ 
           var itemValue = scope.getValueMapper(item); 
           if(itemValue == modelValue){ 
            scope.selectionModel = item; 
            return false; 
           } 
          }); 
         } 
        } 

        if(scope.isMultiple){ 
         scope.$watchCollection(attrs.ngModel, function(modelValue, oldValue) { 
          scope.updateValueFromModel(modelValue); 
         }); 
        }else{ 
         scope.$watch(attrs.ngModel, function(modelValue){ 
          scope.updateValueFromModel(modelValue); 
         }); 
        } 

        //watch the items in case of async loading 
        //scope.$watch(attrs.items, function(){ 
        // scope.updateValueFromModel(scope.ngModel.$modelValue); 
        //}); 

        scope.onItemSelect = function(item, model){ 
         var movelValue = scope.getValueMapper(item); 
         if(scope.isMultiple){ 
          scope.ngModel.$viewValue.push(movelValue); 
         }else{ 
          scope.ngModel.$setViewValue(movelValue); 
         } 
        } 

        scope.onItemRemove = function(item, model){ 
         var removedModelValue = scope.getValueMapper(item); 
         if(scope.isMultiple){ 
          var removeIndex = null; 
          angular.forEach(scope.ngModel.$viewValue, function(itemValue, index){ 
           if(itemValue == removedModelValue){ 
            removeIndex = index; 
            return false; 
           } 
          }); 
          if(removeIndex){ 
           scope.ngModel.$viewValue.splice(removeIndex, 1); 
          } 
         }else{ 
          scope.ngModel.$setViewValue(movelValue); 
         } 
        } 

       } 
      } 
     }; 
    }]) 

.run(['$templateCache', function ($templateCache) { 
     $templateCache.put('/global/dg-ui/dg-select.tpl.html', 
      '<ui-select class="ui-select" ng-model="selectionModel" on-select="onItemSelect($item, $model)" on-remove="onItemRemove($item, $model)" ng-disabled="disabled"><ui-select-match></ui-select-match><ui-select-choices></div></ui-select-choices></ui-select>'); 
     $templateCache.put('/global/dg-ui/dg-select-multi.tpl.html',  '<ui-select class="ui-select" multiple ng-model="selectionModel" on-select="onItemSelect($item, $model)" on-remove="onItemRemove($item, $model)" ng-disabled="disabled"><ui-select-match></ui-select-match><ui-select-choices></ui-select-choices></ui-select>'); 
    }]); 

Возможно, я делаю что-то неправильно здесь. Я был бы очень признателен за любую помощь :), спасибо!

ответ

0

В ui-select уже есть такие функции. Так просто указать свойство в ретранслятора следующим образом:

repeat="item.indexProp as item in myCtrl.items" 

И вся разметка может выглядеть следующим образом:

<ui-select ng-model="myCtrl.selectedItem" theme="select2"> 
    <ui-select-match placeholder="Select an item...">{{$select.selected.captionProp}}</ui-select-match> 
    <ui-select-choices repeat="item.indexProp as item in myCtrl.items | filter: $select.search" value=" {{$select.selected.indexProp}}"> 
    <div ng-bind-html="item.captionProp | highlight: $select.search"></div> 
    </ui-select-choices> 
</ui-select> 

Так что, если ваш деталь выглядит следующим образом:

{indexProp: 1, captionProp: 'Item Name'}

ui-select отобразит «captionProp» в раскрывающемся меню и передаст «indexProp» в вашу ng-модель.

+0

Большое спасибо, вот и думаю, что я ищу :). –