我最近更新了Angular 1.2.0rc1到Angular 1.2.5的解决方案。
我们正在使用AngularUI为下拉列表提供Select2 ajax功能。在从Angular 1.2.0rc1更新之前,一切正常; Select2将处理ajax调用并加载下拉数据,选择一个对象将填充该表单元素。
现在我们已经更新到1.2.5,ajax功能仍在加载数据 - 但是选择不会更新附加到带有ui-select2
绑定的输入的ng模型。因此,表单无法验证(因为该字段是必需的),用户无法继续。
我一直在研究这个,一个可能的解决方案是重写解决方案以使用常规select2下拉列表,使用<select>
和<option data-ng-repeat="each in myModel">
标记并使用Angular自己的AJAX功能将数据附加到myModel
。但是,我预见到这个问题(处理滚动等),我正在寻找一个更简单,更快速的解决方案。
之前是否有人遇到此问题?任何人都可以对这种情况有所了解吗?
答案 0 :(得分:2)
在测试过程中,我发现模型上有一个$scope.watch
用于此表单输入。事实证明,watch函数将运行三次 - 第一次使用正确的对象值;第二次,用字符串“Object object”作为对象的表示;第三次,空值。我通过检查newValue
数据类型来修改它 - 如果它是一个字符串,则将模型重置为旧值。然而,虽然这有效,但我仍然不确定为什么简单地更改库会导致这种退化。
如果我有时间,我打算尝试使用简化的测试用例重现这一点。
更新2:我找到this question,这解释了这不起作用的根本原因。因此,看起来可以在指令上设置优先级并调用render函数。
代码就是这样:
angular.module('ui.select2', []).value('uiSelect2Config', {}).directive('uiSelect2', ['uiSelect2Config', '$timeout',
function (uiSelect2Config, $timeout) {
var options = {};
if (uiSelect2Config) {
angular.extend(options, uiSelect2Config);
}
return {
require: 'ngModel',
priority: 1, // This fixed it.
compile: function (tElm, tAttrs) {
......
我们在我们的解决方案中使用了这个,虽然它并不完美(在某些情况下仍然存在数据绑定的一些问题; Select2喜欢因某些原因而返回字符串而不是对象)我们已经能够使它工作。
更新:我认为我在AngularUI的select2.js中发现了潜在的问题。
source code将以下内容定义为convertToSelect2Model
下select2指令的一部分:
if (controller) {
// Watch the model for programmatic changes
scope.$watch(tAttrs.ngModel, function (current, old) {
if (!current) {
return;
}
if (current === old) {
return;
}
controller.$render();
}, true);
controller.$render = function () {
if (isSelect) {
elm.select2('val', controller.$viewValue);
} else {
if (opts.multiple) {
var viewValue = controller.$viewValue;
if (angular.isString(viewValue)) {
viewValue = viewValue.split(',');
}
elm.select2(
'data', convertToSelect2Model(viewValue));
} else {
if (angular.isObject(controller.$viewValue)) {
elm.select2('data', controller.$viewValue);
} else if (!controller.$viewValue) {
elm.select2('data', null);
} else {
elm.select2('val', controller.$viewValue);
}
}
}
};
在旧版Angular中,这一切都很好。但是,对于Angular 1.2.5,这不起作用; $render
函数实际上已经由Angular定义,因此永远不会调用写入的函数。将controller.$render
函数重命名为controller.$renderui
可修复基础问题。这是我的修复:
if (controller) {
controller.$renderui = function () {
if (isSelect) {
elm.select2('val', controller.$viewValue);
} else {
if (opts.multiple) {
elm.select2(
'data', convertToSelect2Model(controller.$viewValue));
} else {
if (angular.isObject(controller.$viewValue)) {
elm.select2('data', controller.$viewValue);
} else if (!controller.$viewValue) {
elm.select2('data', null);
} else {
elm.select2('val', controller.$viewValue);
}
}
}
};
// Watch the model for programmatic changes
scope.$watch(tAttrs.ngModel, function (current, old) {
if (!current) {
return
}
if (current == old) {
return
}
controller.$renderui();
}, true)
这解决了我遇到的很多问题,我遇到了Select2(在我的项目中使用)和绑定到ng模型(现在,当ng模型更改时,Select2将正确更新),包括我原来的问题
TLDR:AngularUI select2尝试定义controller.$render
,但该功能已由Angular 1.2.5内部定义,并且尝试重新定义它似乎不起作用。重命名功能似乎解决了这个问题。
我希望这有助于某人。