Directive de sélection Angularjs, problèmes $ digest
-
20-12-2019 - |
Question
J'ai du mal à utiliser watch à l'intérieur d'une directive avec un plugin tiers appelé selectize.
J'ai beaucoup lu sur $digest/$watch, mais j'ai toujours des problèmes.
Mon exemple ci-dessous "fonctionne", mais j'essaie d'empêcher le $digest already in progress
les erreurs.
Il y a peut-être une meilleure façon d’aborder cela, mais je ne sais tout simplement pas comment.
plongeur: 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);
});
}
};
});
La solution
Essayez d'encapsuler les appels vers le tiers dans un $timeout comme celui-ci :
$timeout(function() {
// clear options
selectize.clear();
selectize.clearOptions();
// add options
angular.forEach(newTags, function(tag) {
selectize.addOption(tag);
});
}, 0);
Et n'oubliez pas d'injecter $timeout.
Avec un délai d'attente de zéro (en laissant de côté la valeur par défaut à 0 également…), je croire ceci est garanti pour s'exécuter lors de la prochaine boucle de résumé, évitant ainsi les erreurs déjà en cours.Quelqu'un peut-il intervenir si cela est correct, mais j'ai utilisé cette astuce pour résoudre les erreurs de résumé lors de l'appel de certaines fonctions javascript tierces (tinyMce).
Voir l'explication de betaorbust dans ce post SO : AngularJS :Empêcher l'erreur $digest déjà en cours lors de l'appel de $scope.$apply()
Autres conseils
J'ai récemment créé une directive pour Selectize qui prend en charge la liaison bidirectionnelle du modèle et des options.J'ai également dû utiliser $timeout.
https://github.com/machineboy2045/angular-selectize
http://plnkr.co/edit/twGAfU?p=preview
Voici les parties essentielles de la directive.J'ai supprimé certaines fonctionnalités supplémentaires de la version complète.
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);
})
}
}
};
});