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);
    });
  }
};
});
Était-ce utile?

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); 
        })
      }
    }
  };
});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top