我在指令中使用watch以及名为selectize的第三方插件时遇到了麻烦。
我已经阅读了很多关于$ digest / $ watch的内容,但我仍然遇到问题。
下面的示例“有效”,但我正在尝试阻止$digest already in progress
错误。
可能有更好的方法来解决这个问题,我只是不确定是怎么做的。
plunker :http://plnkr.co/edit/3JjTsEU2BlxPWHtw6HaW?p=preview
app.directive('selectize', function($parse) {
return {
restrict: 'A',
require: ['ngModel'],
scope: {
ngModel: '=',
options: '='
},
link: function(scope, el, attrs) {
var $select = el.selectize({
valueField: 'id',
labelField: 'name'
});
var selectize = $select[0].selectize;
// add options
angular.forEach('options', function(tag) {
selectize.addOption(tag);
});
scope.$watchCollection('options', function(newTags, oldTags) {
// why are these the same objects?
console.log('newTags', newTags);
console.log('oldTags', oldTags);
if (newTags !== oldTags) {
// clear options
selectize.clear();
selectize.clearOptions();
// add options
angular.forEach(newTags, function(tag) {
selectize.addOption(tag);
});
}
});
// if value changes without selecting an option,
// set the option to the new model val
scope.$watch('ngModel', function(val) {
console.log('val', val);
// selectize.setValue(val);
});
}
};
});
答案 0 :(得分:6)
尝试将调用包装到$ timeout内的第三方,如下所示:
$timeout(function() {
// clear options
selectize.clear();
selectize.clearOptions();
// add options
angular.forEach(newTags, function(tag) {
selectize.addOption(tag);
});
}, 0);
不要忘记注入$ timeout。
超时为零(除了默认值为0 ......),我相信这保证在下一个摘要循环期间运行,从而防止已经在进行中的错误。如果这是正确的话,有人请插入,但我在调用某些第三方(tinyMce)javascript函数时使用了这个技巧来解决摘要错误。
请参阅此SO帖子中的betaorbust解释:AngularJS : Prevent error $digest already in progress when calling $scope.$apply()
答案 1 :(得分:1)
我最近为Selectize创建了一个指令,它支持模型和选项的双向绑定。我还必须使用$ timeout。
https://github.com/machineboy2045/angular-selectize
http://plnkr.co/edit/twGAfU?p=preview
这是该指令的基本部分。我删除了完整版中的一些其他功能。
app.directive('selectize', function($timeout) {
return {
restrict: 'A',
require: '^ngModel',
link: function(scope, element, attrs, ngModel) {
var config = scope.$eval(attrs.selectize);
config.options = scope.$eval(attrs.options) || [];
element.selectize(config);
var selectize = element[0].selectize;
selectize.on('option_add', refreshAngularOptions);
scope.$watch(function(){ return ngModel.$modelValue}, refreshSelectize, true)
function refreshAngularOptions(value, data) {
config.options = selectize.options;
}
function createOption(opt){
var newOpt = {};
newOpt[selectize.settings.valueField] = opt;
newOpt[selectize.settings.labelField] = opt;
selectize.addOption(newOpt);
}
function refreshSelectize(value){
$timeout(function(){
if(angular.isArray(value))
angular.forEach(value, createOption);
else
createOption(value);
selectize.refreshOptions(false);
selectize.setValue(value);
})
}
}
};
});