I'm having trouble using watch inside of a directive along with a 3rd party plugin called selectize.
I've read a lot about $digest/$watch, but am still having problems.
My example below "works", but i'm trying to prevent the $digest already in progress
errors.
There may be a better way to approach this, im just not sure how too.
plunker:
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);
});
}
};
});
I'm having trouble using watch inside of a directive along with a 3rd party plugin called selectize.
I've read a lot about $digest/$watch, but am still having problems.
My example below "works", but i'm trying to prevent the $digest already in progress
errors.
There may be a better way to approach this, im just not sure how too.
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);
});
}
};
});
Share
Improve this question
edited Feb 25, 2014 at 0:38
Chen-Tsu Lin
23.3k16 gold badges56 silver badges65 bronze badges
asked Feb 24, 2014 at 23:56
tuurbotuurbo
3615 silver badges14 bronze badges
4
- May be just switch to select2 ? There is nice wrapper for it in angular-ui – vittore Commented Feb 25, 2014 at 0:41
- Which part of your code is triggering the digest already in progress errors? – Sunil D. Commented Feb 25, 2014 at 0:53
-
@SunilD. It seems like its
selectize.clear();selectize.clearOptions();
that triggers it – tuurbo Commented Feb 25, 2014 at 1:28 - @vittore i could, but i would like to learn from this – tuurbo Commented Feb 25, 2014 at 1:30
2 Answers
Reset to default 6Try wrapping the calls to the 3rd party inside a $timeout like this:
$timeout(function() {
// clear options
selectize.clear();
selectize.clearOptions();
// add options
angular.forEach(newTags, function(tag) {
selectize.addOption(tag);
});
}, 0);
And don't forget to inject $timeout.
With a timeout of zero (leaving out the value defaults to 0 as well…), I believe this is guaranteed to run during the next digest loop, thus preventing the already in progress errors. Someone please chime in if that is correct, but I have used this trick to solve the digest errors when calling some third party (tinyMce) javascript functions.
See betaorbust's explanation in this SO post: AngularJS : Prevent error $digest already in progress when calling $scope.$apply()
I recently created a directive for Selectize that supports 2-way binding of the model and the options. I also had to use $timeout.
https://github./machineboy2045/angular-selectize
http://plnkr.co/edit/twGAfU?p=preview
Here's the essential parts of the directive. I stripped out some additional functionality that's in the full version.
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);
})
}
}
};
});
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744655208a4586140.html
评论列表(0条)