用 angularjs 自定义指令包装 ui-select
Wrapping ui-select with angularjs custom directive
是的,在 SO 上有几个类似的问题,但是 none 似乎解决了我的问题(或者使用 Angular 1.5.8 和 [=53= 的最新版本] 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);
我在这里创建了问题的 Plunker:
https://plnkr.co/edit/Yn1qhMjKuij7FM8Unpad
请注意,当您向顶部控件添加标签时,它会更新底部控件中的数据模型。但是,当您将标签添加到底部控件时,它会停止更新数据模型。我怀疑这与使用 ng-model
.
绑定模型的方式有关
非常感谢任何帮助。
FWIW,这个线程与我的问题最相似: 然而,当我尝试模仿这个解决方案时,它只会让我达到现在的状态。
所以我找到了一个解决方案,我有点理解"why"它有效但不能 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
:
标签-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>
这里有一个 link 功能正常的 Plunkr:https://plnkr.co/edit/Eq9pIl8KoHZ2PuTa2PLu?p=preview
我怀疑 ui-select 中的某些东西正在破坏范围,但不确定如何在不付出大量额外努力的情况下证明或追踪它。
是的,在 SO 上有几个类似的问题,但是 none 似乎解决了我的问题(或者使用 Angular 1.5.8 和 [=53= 的最新版本] 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);
我在这里创建了问题的 Plunker: https://plnkr.co/edit/Yn1qhMjKuij7FM8Unpad
请注意,当您向顶部控件添加标签时,它会更新底部控件中的数据模型。但是,当您将标签添加到底部控件时,它会停止更新数据模型。我怀疑这与使用 ng-model
.
非常感谢任何帮助。
FWIW,这个线程与我的问题最相似:
所以我找到了一个解决方案,我有点理解"why"它有效但不能 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
:
标签-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>
这里有一个 link 功能正常的 Plunkr:https://plnkr.co/edit/Eq9pIl8KoHZ2PuTa2PLu?p=preview
我怀疑 ui-select 中的某些东西正在破坏范围,但不确定如何在不付出大量额外努力的情况下证明或追踪它。