扩展角度指令


114

我想对第3方指令(特别是Angular UI Bootstrap)进行较小的修改。我只是想添加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
  };
}]);

但是我也想让Bower与Angular-Bootstrap保持同步。运行后bower update,我将覆盖所做的更改。

那么,如何与该Bower组件分开扩展该指令?


2
干净的方法是使用$provide.decorator(),看我的回答如下。
伊莱兰·马尔卡

Answers:


96

解决此问题的最简单方法可能是在您的应用上创建与第三方指令同名的指令。这两个指令都将运行,并且您可以使用priority属性指定运行顺序(优先级更高的优先运行)。

这两个指令将共享作用域,您可以通过您的指令的访问和修改第三方指令的作用域 link方法。

选项2:您也可以通过简单地将自己任意命名的指令放在与它相同的元素上来访问第三方指令的作用域(假设这两个指令都不使用隔离作用域)。元素上的所有非隔离作用域指令都将共享作用域。

进一步阅读: https : //github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

注意:我以前的答案是修改第三方服务,而不是指令。


3
谢谢@ sh0ber,这正是我所需要的。您先前的回答对我也有帮助,例如:3rdparty服务。
凯尔2013年

嘿,这个答案确实很好,但是我找不到关于指令的“ priority”属性的任何文档。我发现的只是一个标语“您可以使用它”,但是找不到任何实际示例。
Ciel 2014年

2
@Ciel该指令API信息显然已经移到$compile文档在这里

60

TL; DR-gimme tha演示!


     Big Demo Button     
 


$providedecorator(),好了,装点第三方的指令。

在我们的例子中,我们可以像下面这样扩展指令的范围:

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

首先,我们要求pane通过传递指令名称来修饰该指令,并将其Directive作为第一个参数进行连接,然后从回调参数(这是与该名称匹配的指令数组)中检索指令。

一旦获得它,就可以获取其作用域对象并根据需要对其进行扩展。注意,所有这些都必须在代码config块中完成。

一些注意事项

  • 建议仅添加具有相同名称的指令,然后设置其优先级。除了不语义化(我至不知道这是一个词)之外,它还带来一些问题,例如,如果第三方指令的优先级发生变化该怎么办?

  • JeetendraChauhan声称(尽管我尚未对其进行测试)该解决方案在1.13版中不起作用。


1
我建议你给@ sh0ber的答案去(创建另一个仅用于发出事件的指令)。
伊莱兰·马尔卡

2
关于这个答案的简短说明(效果很好),'paneDirective'中的'Directive'确实有目的;-)我花了一段时间才弄清楚:stackoverflow.com/questions/19409017/…,请参见接受回答。
罗伊·米尔德

2
您好@EliranMalka,请检查我的矮人plnkr.co/edit/0mvQjHYjQCFS6joYJdwK 希望对您有所帮助
Jeetendra Chauhan

1

1
@EliranMalka是的,bindToController是在v1.3中引入的。但是请注意,这不应被视为替代解决方案,这仅适用于使用bindToController属性设置原始指令的特定情况。好主意,我将其作为答复:)
gilad mayani


6

另一种解决方案是创建一个新指令,以对其进行扩展而无需修改原始指令

该解决方案类似于装饰器解决方案:

创建一个新指令并将您要扩展的指令作为依赖项注入

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

这样,您可以在同一应用中使用原始指令和扩展版本


2
太好了,这正是我需要使用自己的变量扩展隔离范围指令的地方!我确实发现angular.extend不会对对象进行深度复制,因此将其替换了panelDirective的scope对象。一个替代方法是angular.merge,它将保留PaneDirective的原始范围并添加/合并此处定义的变量。
mathewguest

1
是的,angular.merge应该使用它,我将更新示例
kidroca

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.