web-dev-qa-db-fra.com

Extension Angular

Je voudrais apporter une modification mineure à une directive tierce (en particulier Angular UI Bootstrap ). Je veux simplement ajouter à la portée de la directive pane:

angular.module('ui.bootstrap.tabs', [])
.controller('TabsController', ['$scope', '$element', function($scope, $element) {
  // various methods
}])
.directive('tabs', function() {
  return {
    // etc...
  };
})
.directive('pane', ['$parse', function($parse) {
  return {
    require: '^tabs',
    restrict: 'EA',
    transclude: true,
    scope:{
      heading:'@',
      disabled:'@' // <- ADDED SCOPE PROPERTY HERE
    },
    link: function(scope, element, attrs, tabsCtrl) {
      // link function
    },
    templateUrl: 'template/tabs/pane.html',
    replace: true
  };
}]);

Mais je souhaite également que Angular-Bootstrap soit à jour avec Bower. Dès que je lance bower update, Je vais écraser mes modifications.

Alors, comment puis-je étendre cette directive séparément de cette composante de la tonnelle?

114
Kyle

Le moyen le plus simple de résoudre ce problème consiste probablement à créer une directive portant le même nom que votre directive tierce sur votre application. Les deux directives seront exécutées et vous pouvez spécifier leur ordre d'exécution à l'aide de la propriété priority (la priorité la plus élevée est exécutée en premier).

Les deux directives partageront la même portée et vous pouvez accéder à la portée de la directive tierce et la modifier via la méthode link de votre directive.

Option 2: Vous pouvez également accéder à la portée d'une directive tierce en plaçant simplement votre propre directive nommée de manière arbitraire sur le même élément (en supposant qu'aucune de ces directives n'utilise isolat portée). Toutes les directives de portée non isolées sur un élément partagent la même portée.

Lectures supplémentaires: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

Remarque: Ma réponse précédente concernait la modification d'un service tiers, et non d'une directive.

96
Dan

TL; DR - Donne-moi cette démo!


Grand bouton de démonstration


Utilisez les decorator() de $provide Pour bien décorer la directive du tiers.

Dans notre cas, nous pouvons étendre le champ d'application de la directive comme suit:

app.config(function($provide) {
    $provide.decorator('paneDirective', function($delegate) {
        var directive = $delegate[0];
        angular.extend(directive.scope, {
            disabled:'@'
        });
        return $delegate;
    });
});

Tout d'abord, nous demandons de décorer la directive pane en passant son nom, concaténé avec Directive comme premier argument, puis nous le récupérons à partir du paramètre callback (qui est un tableau de directives correspondant à ce nom). ).

Une fois que nous l'avons, nous pouvons obtenir son objet scope et l'étendre si nécessaire. Notez que tout cela doit être fait dans le bloc config.

Quelques notes

  • Il a été suggéré d'ajouter simplement une directive du même nom, puis de définir son niveau de priorité. En plus d'être peu sémantique (ce qui est même pas un mot , je sais…), cela pose des problèmes, par exemple. Et si le niveau de priorité de la directive tierce change?

  • JeetendraChauhan a affirmé (je ne l'ai pas encore testé) que cette solution ne fonctionnerait pas dans la version 1.13.

60
Eliran Malka

Bien que ce ne soit pas la réponse directe à votre question, vous voudrez peut-être savoir que la dernière version (en maître) de http://angular-ui.github.io/bootstrap/ prise en charge supplémentaire de la désactivation des onglets . Cette fonctionnalité a été ajoutée via: https://github.com/angular-ui/bootstrap/commit/2b78dd16abd7e09846fa484331b5c35ece6619a2

8

Une autre solution où vous créez une nouvelle directive qui l'étend sans modifier la directive d'origine

La solution est similaire à la solution de décorateur:

Créer une nouvelle directive et injecter comme dépendance la directive que vous souhaitez étendre

app.directive('extendedPane', function (paneDirective) {

  // to inject a directive as a service append "Directive" to the directive name
  // you will receive an array of directive configurations that match this 
  // directive (usually only one) ordered by priority

  var configExtension = {
     scope: {
       disabled: '@'
     }
  }

  return angular.merge({}, paneDirective[0], configExtension)
});

De cette façon, vous pouvez utiliser la directive d'origine et la version étendue dans la même application.

6
kidroca

Voici une autre solution pour un scénario différent consistant à étendre les liaisons à une directive ayant la propriété bindToController.

Remarque: Il ne s'agit pas d'une alternative aux autres solutions proposées ici. Cela ne résout qu'un cas spécifique (non traité dans d'autres réponses) dans lequel la directive d'origine a été configurée avec bindToController.

1
gilad mayani