web-dev-qa-db-fra.com

Directive AngularJS avec options par défaut

Je commence tout juste avec angularjs et je travaille à la conversion de quelques anciens plugins JQuery en directives Angular. J'aimerais définir un ensemble d'options par défaut pour ma directive (élément), qui peut être remplacé en spécifiant la valeur de l'option dans un attribut.

J'ai jeté un œil autour de la façon dont d'autres l'ont fait, et dans la bibliothèque angular-ui , la i.bootstrap.pagination semble faire quelque chose de similaire.

Toutes les options par défaut sont d'abord définies dans un objet constant:

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

Ensuite, une fonction utilitaire getAttributeValue est associée au contrôleur de directive:

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

Enfin, cela est utilisé dans la fonction de liaison pour lire les attributs en tant que

.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 vouloir remplacer un ensemble de valeurs par défaut. Y a-t-il d'autres moyens de faire cela qui sont courants? Ou est-il normal de toujours définir une fonction utilitaire telle que getAttributeValue et d'analyser les options de cette manière? Je suis intéressé à savoir quelles sont les différentes stratégies que les gens ont pour cette tâche commune.

De plus, en prime, je ne comprends pas pourquoi le paramètre interpolate est requis.

142
Ken Chatfield

Vous pouvez utiliser compile fonction - lire les attributs s’ils ne sont pas définis - les renseigner avec les 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; }
    },
        ...
  }
});
107
OZ_

Utilisez l'indicateur =? 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';
      }
    }
  });
254
Hunter

J'utilise AngularJS v1.5.10 et j'ai trouvé que preLink fonction de compilation fonctionnait plutôt bien pour la définition des valeurs d'attribut par défaut.

Juste un rappel:

  • attrs contient les valeurs d'attribut DOM brutes brutes qui sont toujours undefined ou des chaînes.
  • scope contient (entre autres) les valeurs d'attribut DOM analysées en fonction de la spécification de portée d'isolat fournie (=/</@/etc.).

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: ...
  }
});
1
Keego