152 votes

Directive AngularJS avec options par défaut

Je débute avec Angularjs, et je travaille à convertir quelques vieux plugins JQuery en directives Angular. J'aimerais définir un ensemble d'options par défaut pour ma directive (élément), qui peuvent être remplacées en spécifiant la valeur de l'option dans un attribut.

J'ai cherché à savoir comment les autres ont procédé, et dans la section angular-ui bibliothèque le ui.bootstrap.pagination semble faire quelque chose de similaire.

Tout d'abord, toutes les options par défaut sont définies dans un objet constant :

.constant('paginationConfig', {
  itemsPerPage: 10,
  boundaryLinks: false,
  ...
})

Alors un getAttributeValue La fonction utilitaire est attachée au contrôleur de directives :

this.getAttributeValue = function(attribute, defaultValue, interpolate) {
    return (angular.isDefined(attribute) ?
            (interpolate ? $interpolate(attribute)($scope.$parent) :
                           $scope.$parent.$eval(attribute)) : defaultValue);
};

Enfin, il est utilisé dans la fonction de liaison pour lire les attributs comme suit

.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
    ...
    controller: 'PaginationController',
    link: function(scope, element, attrs, paginationCtrl) {
        var boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks,  config.boundaryLinks);
        var firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true);
        ...
    }
});

Cela semble être une configuration plutôt compliquée pour quelque chose d'aussi standard que de vouloir remplacer un ensemble de valeurs par défaut. Existe-t-il d'autres façons courantes de procéder ? Ou est-il normal de toujours définir une fonction utilitaire telle que getAttributeValue et analyser les options de cette manière ? J'aimerais savoir quelles sont les différentes stratégies utilisées par les gens pour cette tâche commune.

En outre, en prime, je ne comprends pas bien pourquoi la interpolate est nécessaire.

271voto

Hunter Points 631

Utilisez le =? pour la propriété dans le bloc scope de la directive.

angular.module('myApp',[])
  .directive('myDirective', function(){
    return {
      template: 'hello {{name}}',
      scope: {
        // use the =? to denote the property as optional
        name: '=?'
      },
      controller: function($scope){
        // check if it was defined.  If not - set a default
        $scope.name = angular.isDefined($scope.name) ? $scope.name : 'default name';
      }
    }
  });

5 votes

=? est disponible depuis la version 1.1.x

35 votes

Si votre attribut pouvait accepter true o false comme valeurs, vous voudriez (je pense) utiliser par exemple $scope.hasName = angular.isDefined($scope.hasName) ? $scope.hasName : false; à la place.

0 votes

Wow, c'est une solution vraiment propre. Je n'ai pas pu trouver un aussi bon exemple d'utilisation des valeurs par défaut dans les documents d'Angular. +1 !

111voto

OZ_ Points 7398

Vous pouvez utiliser compile fonction - lire les attributs s'ils ne sont pas définis - les remplir avec des valeurs par défaut.

.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
    ...
    controller: 'PaginationController',
    compile: function(element, attrs){
       if (!attrs.attrOne) { attrs.attrOne = 'default value'; }
       if (!attrs.attrTwo) { attrs.attrTwo = 42; }
    },
        ...
  }
});

1 votes

Merci ! Alors, comment expliquer que ui.bootstrap.pagination fait les choses de manière plus compliquée ? Je pensais qu'en utilisant la fonction de compilation, les modifications d'attributs effectuées ultérieurement ne seraient pas prises en compte, mais cela ne semble pas être le cas, car seules les valeurs par défaut sont définies à ce stade. Je suppose qu'il doit y avoir un compromis à faire ici.

3 votes

@KenChatfield dans compile vous ne pouvez pas lire les attributs, qui doivent être interpolés pour obtenir la valeur (qui contient l'expression). Mais si vous voulez vérifier seulement si l'attribut est vide - cela fonctionnera sans aucun compromis pour vous (avant l'interpolation, l'attribut contiendra une chaîne avec l'expression).

1 votes

Fantastique ! Merci beaucoup pour votre explication claire. Pour les futurs lecteurs, bien que cela soit en rapport avec la question initiale, pour une explication de ce que fait le paramètre " interpoler " dans la fonction ui.bootstrap.pagination exemple J'ai trouvé cet exemple très utile : jsfiddle.net/EGfgH

2voto

Keego Points 1256

J'utilise AngularJS v1.5.10 et j'ai trouvé l'erreur suivante preLink fonction de compilation fonctionne plutôt bien pour définir les valeurs par défaut des attributs.

Juste un rappel :

  • attrs détient le brut Les valeurs des attributs DOM qui sont toujours soit undefined ou des chaînes de caractères.
  • scope contient (entre autres) les valeurs des attributs DOM analysé conformément à la spécification de l'étendue de l'isolement fournie ( = / < / @ / etc.).

Un extrait abrégé :

.directive('myCustomToggle', function () {
  return {
    restrict: 'E',
    replace: true,
    require: 'ngModel',
    transclude: true,
    scope: {
      ngModel: '=',
      ngModelOptions: '<?',
      ngTrueValue: '<?',
      ngFalseValue: '<?',
    },
    link: {
      pre: function preLink(scope, element, attrs, ctrl) {
        // defaults for optional attributes
        scope.ngTrueValue = attrs.ngTrueValue !== undefined
          ? scope.ngTrueValue
          : true;
        scope.ngFalseValue = attrs.ngFalseValue !== undefined
          ? scope.ngFalseValue
          : false;
        scope.ngModelOptions = attrs.ngModelOptions !== undefined
          ? scope.ngModelOptions
          : {};
      },
      post: function postLink(scope, element, attrs, ctrl) {
        ...
        function updateModel(disable) {
          // flip model value
          var newValue = disable
            ? scope.ngFalseValue
            : scope.ngTrueValue;
          // assign it to the view
          ctrl.$setViewValue(newValue);
          ctrl.$render();
        }
        ...
    },
    template: ...
  }
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X