使用angularjs自定义指令包装ui-select

时间:2016-09-13 06:41:05

标签: angularjs angularjs-directive angular-ui-select

是的,在SO上有几个类似的问题,但似乎都没有解决我的问题(或者使用最新版本的Angular 1.5.8和Angular UI-Select 1.4.x)。

我遇到的问题是双向数据绑定。当我尝试将我的模型绑定到ui-select时,如果我在没有包含ui-select的指令的情况下执行它,它就可以工作。但是,当我使用包装的ui-select时,它会在一个方向上更新,直到我在指令中修改模型。

的index.html

  <div class="form-group">
    <label class="control-label" for="TEST">TEST</label>
    <ui-select id="TEST" multiple="" ng-model="vm.selectedInstrument.gradeLevels" theme="bootstrap" close-on-select="false" append-to-body="true" style="min-width: 250px">
      <ui-select-match placeholder="THIS IS A TEST">{{$item.name}}</ui-select-match>
      <ui-select-choices repeat="opt in vm.gradeLevelList | filter:$select.search">
        <div ng-bind-html="opt.name | highlight: $select.search"></div>
      </ui-select-choices>
    </ui-select>
    <span class="help-block">
          {{vm.selectedInstrument | json}}
      </span>
  </div>
  <tag-input ng-model="vm.selectedInstrument.gradeLevels" placeholder="Select one or more..." label-text="Grade Levels" options="vm.gradeLevelList" ele-id="gradeLevelTagInput"></tag-input>

代码输入-directive.js

(function () {
    'use strict';

    angular.module('surveyexplorer')
        .directive('tagInput', tagInput);

    function tagInput() {
        return {
            restrict: 'E',
            templateUrl: 'tag-input.html',
            scope: {
                options: '=',
                editMode: '=',
                labelText: '@',
                eleId: '@s',
                placeholder: "@"
            },
            require: ['?ngModel'],
            link: function (scope, elem, attrs, ctrls) {
                var ngModelCtrl = ctrls[0];
                ngModelCtrl.$render = function() {
                    scope.innerModel = ngModelCtrl.$viewValue;
                };

                scope.$watch('innerModel', function(newval, oldval){
                   if (newval !== oldval) {
                       ngModelCtrl.$setViewValue(newval);
                   }
                });
            }
        };
    }
})();

代码-input.html

<div class="form-group">
    <label class="control-label" for="{{eleId}}">{{labelText}}</label>

    <ui-select id="{{eleId}}" multiple ng-model="innerModel" theme="bootstrap" close-on-select="false"
               append-to-body="true" style="min-width: 250px">
        <ui-select-match placeholder="{{placeholder}}">{{$item.name}}</ui-select-match>
        <ui-select-choices repeat="opt in options | filter:$select.search" class="scrollable-menu">
            <div ng-bind-html="opt.name | highlight: $select.search"></div>
        </ui-select-choices>
    </ui-select>
    <span class="help-block">
        {{innerModel}}
    </span>
</div>

的script.js

(function(angular) {
  'use strict';
angular.module('surveyexplorer', [
        'ngSanitize',
        'ngAnimate',
        'ui.bootstrap',
        'ui.select',
        ])
  .controller('InstrumentCtrl', [function() {

    var vm = this;
    vm.selectedInstrument = {
      gradeLevels: []
    };

    vm.gradeLevelList = [{
        "code": "IT",
        "name": "Infant/toddler",
        "sortOrder": 1000,
        "gradeLevelId": 1
    }, {
        "code": "PR",
        "name": "Preschool",
        "sortOrder": 2000,
        "gradeLevelId": 2
    }, {
        "code": "PK",
        "name": "Prekindergarten",
        "sortOrder": 3000,
        "gradeLevelId": 3
    }, {
        "code": "TK",
        "name": "Transitional Kindergarten",
        "sortOrder": 4000,
        "gradeLevelId": 4
    }, {
        "code": "KG",
        "name": "Kindergarten",
        "sortOrder": 5000,
        "gradeLevelId": 5
    }, {
        "code": "1",
        "name": "First grade",
        "sortOrder": 6000,
        "gradeLevelId": 6
    }, {
        "code": "2",
        "name": "Second grade",
        "sortOrder": 7000,
        "gradeLevelId": 7
    }, {
        "code": "3",
        "name": "Third grade",
        "sortOrder": 8000,
        "gradeLevelId": 8
    }, {
        "code": "4",
        "name": "Fourth grade",
        "sortOrder": 9000,
        "gradeLevelId": 9
    }, {
        "code": "5",
        "name": "Fifth grade",
        "sortOrder": 10000,
        "gradeLevelId": 10
    }];

  }]);

})(window.angular);

我在这里创建了一个问题: https://plnkr.co/edit/Yn1qhMjKuij7FM8Unpad

请注意,当您向顶部控件添加标记时,它会更新底部控件中的数据模型。但是,当您向底部控件添加标记时,它会停止更新数据模型。我怀疑它与使用ng-model绑定模型的方式有关。

任何帮助都慷慨地赞赏。

FWIW,这个帖子与我的问题最相似:angularjs pass ngModel from wrapper directive to wrapped directive但是当我试图模仿这个解决方案时,它只能让我到现在为止。

1 个答案:

答案 0 :(得分:1)

所以我找到了一个解决方案,我有点理解&#34;为什么&#34;它有效,但不是100%确定原因。

首先,我简化了指令:

代码输入-directive.html

(function () {
    'use strict';

    angular.module('surveyexplorer')
        .directive('tagInput', tagInput);

    function tagInput() {
        return {
            restrict: 'E',
            templateUrl: 'tag-input.html',
            scope: {
                ngModel: '=',
                options: '=',
                editMode: '=',
                labelText: '@',
                eleId: '@s',
                placeholder: "@"
            },
            controller: function($scope) {
              $scope.innerModel = $scope;
            }
        };
    }
})();

我所做的就是将传入的范围分配给控制器函数中范围本身的属性:

controller: function($scope) {
  $scope.innerModel = $scope;
}

然后我更新了模板中对ngModel的引用,以使用innerModel.ngModel

tag-input.html

<div class="form-group">
    <label class="control-label" for="{{eleId}}">{{labelText}}</label>

    <ui-select id="{{eleId}}" multiple ng-model="innerModel.ngModel" theme="bootstrap" close-on-select="false"
               append-to-body="true" style="min-width: 250px">
        <ui-select-match placeholder="{{placeholder}}">{{$item.name}}</ui-select-match>
        <ui-select-choices repeat="opt in options | filter:$select.search" class="scrollable-menu">
            <div ng-bind-html="opt.name | highlight: $select.search"></div>
        </ui-select-choices>
    </ui-select>
    <span class="help-block">
        {{innerModel.ngModel}}
    </span>
</div>

这是指向正常运作的Plunkr的链接:https://plnkr.co/edit/Eq9pIl8KoHZ2PuTa2PLu?p=preview

我怀疑ui-select中的某些东西正在破坏范围,但不太确定如何在没有太多额外努力的情况下证明或追踪它。