【问题标题】:Wrapping ui-select with angularjs custom directive用 angularjs 自定义指令包装 ui-select
【发布时间】:2016-09-13 06:41:05
【问题描述】:

是的,在 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>

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);
                   }
                });
            }
        };
    }
})();

tag-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);

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

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

非常感谢任何帮助。

FWIW,这个线程与我的问题最相似:angularjs pass ngModel from wrapper directive to wrapped directive 但是当我尝试模仿这个解决方案时,它只会让我明白我现在的状态。

【问题讨论】:

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


    【解决方案1】:

    所以我找到了一个解决方案,我有点理解“为什么”它有效,但不是 100% 确定为什么。

    首先,我简化了指令:

    tag-input-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 中的某些东西正在破坏范围,但不太确定如何在不付出大量额外努力的情况下证明或追踪这一点。

    【讨论】:

    • 非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    • 2016-05-03
    • 1970-01-01
    • 2015-06-21
    相关资源
    最近更新 更多