Extensão da Diretiva Angular

114

Eu gostaria de fazer uma pequena modificação em uma diretiva de terceiros (especificamente Angular UI Bootstrap ). Desejo simplesmente adicionar ao âmbito da panediretiva:

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
  };
}]);

Mas também quero manter o Angular-Bootstrap atualizado com o Bower. Assim que eu executar bower update, substituirei minhas alterações.

Então, como faço para estender essa diretiva separadamente deste componente do bower?

Kyle
fonte

Respostas:

96

Provavelmente, a maneira mais simples de resolver isso é criar uma diretiva em seu aplicativo com o mesmo nome da diretiva de terceiros. Ambas as diretivas serão executadas e você pode especificar sua ordem de execução usando a prioritypropriedade (é executada primeiro).

As duas diretivas compartilharão o escopo e você pode acessar e modificar o escopo da diretiva de terceiros por meio do linkmétodo da sua diretiva .

Opção 2: você também pode acessar o escopo de uma diretiva de terceiros simplesmente colocando sua própria diretiva nomeada arbitrariamente no mesmo elemento com ela (assumindo que nenhuma diretiva use um escopo isolado). Todas as diretivas de escopo não isoladas em um elemento compartilharão o escopo.

Leitura adicional: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

Nota: Minha resposta anterior foi para modificar um serviço de terceiros, não uma diretiva.

Dan
fonte
60

TL; DR - me dê essa demonstração!


     Big Demo Button     
 


Use $providededecorator() para, assim, decorar directiva do terceiro.

No nosso caso, podemos estender o escopo da diretiva da seguinte forma:

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

Primeiro, pedimos para decorar o pane diretiva passando seu nome, concatenado com Directivecomo o primeiro argumento, então o recuperamos do parâmetro de retorno de chamada (que é uma matriz de diretivas que correspondem a esse nome).

Depois de obtê-lo, podemos obter seu objeto de escopo e estendê-lo conforme necessário. Observe que tudo isso deve ser feito noconfig bloco.

Algumas notas

  • Foi sugerido simplesmente adicionar uma diretiva com o mesmo nome e definir seu nível de prioridade. Além de não ser semântico (que nem mesmo é uma palavra , eu sei ...), ele levanta problemas, por exemplo, e se o nível de prioridade da diretiva de terceiros mudar?

  • JeetendraChauhan afirmou (embora não tenha testado) que esta solução não funcionará na versão 1.13.

Eliran Malka
fonte
6

Outra solução onde você cria uma nova diretiva que a estende sem modificar a diretiva original

A solução é semelhante à solução do decorador:

Crie uma nova diretiva e injete como dependência a diretiva que deseja estender

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)
});

Desta forma, você pode usar a diretiva original e a versão estendida no mesmo aplicativo

Kidroca
fonte
1

Aqui está outra solução para um cenário diferente de estender ligações a uma diretiva que possui a bindToControllerpropriedade.

Nota: esta não é uma alternativa a outras soluções que foram oferecidas aqui. Resolve apenas um caso específico (não coberto em outras respostas) em que a diretiva original foi configurada bindToController.

Gilad Mayani
fonte