扩展 AngularJs 指令

Posted

技术标签:

【中文标题】扩展 AngularJs 指令【英文标题】:Extending AngularJs Directive 【发布时间】:2013-06-05 00:02:10 【问题描述】:

我想对第 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
  ;
]);

但我也想让 Angular-Bootstrap 与 Bower 保持同步。只要我运行bower update,我就会覆盖我的更改。

那么我该如何从这个 bower 组件中单独扩展这个指令呢?

【问题讨论】:

【参考方案1】:

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

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

选项 2: 您还可以访问第三方指令的范围,只需将您自己的任意命名指令放在与其相同的元素上(假设两个指令都没有使用隔离范围)。 一个元素上的所有非隔离作用域指令都将共享作用域。

延伸阅读: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

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

【讨论】:

感谢@sh0ber,这正是我所需要的。您之前的回答也对我有所帮助,回复:第 3 方服务。 嘿,这个答案真的很好,但我找不到任何关于指令“优先级”属性的文档。我只找到了一个宣传语,上面写着“你可以使用它”,但找不到任何实际的例子。 @Ciel 指令 API 信息显然已移至 $compile doc here【参考方案2】:

另一种解决方案,您可以创建一个新指令来扩展它而不修改原始指令

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

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

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

这样你可以在同一个应用程序中使用原始指令和扩展版本

【讨论】:

这很棒,正是我需要用我自己的变量来扩展隔离范围指令!我确实发现 angular.extend 不会对对象进行深度复制,因此它将paneDirective 的范围对象替换为这个对象。另一种方法是 angular.merge,它将保留 PaneDirective 的原始范围并添加/合并此处定义的变量。 是的,应该使用angular.merge,我会更新示例 angualr.merge 已弃用,请参阅docs.angularjs.org/api/ng/function/angular.merge。你应该使用类似 Lodash 的东西(由 AnguarJs 推荐)lodash.com/docs/4.17.15#merge【参考方案3】:

Here is another solution 用于将绑定扩展到具有bindToController 属性的指令的不同场景。

注意:这不是此处提供的其他解决方案的替代方案。它仅解决了原始指令使用bindToController 设置的特定情况(其他答案未涵盖)。

【讨论】:

【参考方案4】:

TL;DR - 给我演示!

     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 块中完成。

一些注意事项

建议简单地添加同名指令,然后设置其优先级。除了没有语义(这是not even a word,我知道......)之外,它还带来了一些问题,例如如果第三方指令的优先级发生变化怎么办?

JeetendraChauhan 声称(虽然我还没有测试过)这个解决方案在 1.13 版中不起作用。

【讨论】:

我建议你试一试@sh0ber 的回答(创建另一个指令,仅用于发出事件)。 关于这个答案的快速说明(效果很好),“paneDirective”中的“指令”确实有目的;-) 我花了一段时间才弄清楚:***.com/questions/19409017/…,见接受的答案。 嗨 @EliranMalka 检查我的 plunker plnkr.co/edit/0mvQjHYjQCFS6joYJdwK 希望这会对某人有所帮助 decorator() 的链接已损坏(更新为docs.angularjs.org/api/auto/service/$provide#decorator) @EliranMalka 是的,bindToController 是在 v1.3 中引入的。但请注意,这不应被视为替代解决方案,这仅适用于使用 bindToController 属性设置原始指令的特定情况。好主意,我会发布这个作为答案:)【参考方案5】:

虽然这不是您问题的直接答案,但您可能想知道http://angular-ui.github.io/bootstrap/ 的最新版本(主版本)添加了对禁用选项卡的支持。此功能是通过以下方式添加的: https://github.com/angular-ui/bootstrap/commit/2b78dd16abd7e09846fa484331b5c35ece6619a2

【讨论】:

+1 提醒。很高兴知道。我猜 bower 的 angular-bootstrap 和 angular-ui 的 bootstrap 组件不同步。

以上是关于扩展 AngularJs 指令的主要内容,如果未能解决你的问题,请参考以下文章

AngularJs——简介,表达式,指令

05AngularJS 指令

JavaScript强化教程——AngularJS 指令

[angularjs] angularjs系列笔记简介

AngularJS

AngularJs 指令