0

ui-select ディレクティブのラッパーである angular ディレクティブを作成しようとしています。私の目標は、選択したアイテムの特定のプロパティと同期するアイテムとモデルのリストをディレクティブに与えることです。私のディレクティブには 5 つの属性があります。

ng-model - モデルを指定するには、
items - アイテムのリストを指定します。
display-prop - 表示目的で ui-select 内で使用されるプロパティの名前
value-prop - モデルの割り当てに使用されるプロパティの名前
multiple [オプション] - 複数選択が許可されている場合

ディレクティブの子スコープには、ui-select ng-model と同期するオブジェクトがあり、それが変更されると、メイン スコープが更新されます。

空の選択から始めると、選択された単一のアイテムと複数のアイテムに対して機能するように管理します。ただし、複数選択が選択されたときに最初に選択されたアイテムを表示するには、まだ問題があります。問題は、私のディレクティブと ui-select ディレクティブの間のスコープと $watch メソッドのどこかにあると思います。配列の場合、ディレクティブ スコープの更新は ui-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>');
    }]);

おそらく私はここで何か間違ったことをしています。助けていただければ幸いです:)、ありがとう!

4

1 に答える 1

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: 'アイテム名'}

ui-select はアイテムの「captionProp」をドロップダウンに表示し、「indexProp」を ng-model に渡します。

于 2014-10-31T14:51:27.617 に答える