你能否在AngularUI Bootstrap中覆盖特定的模板?

90

我想知道是否有办法覆盖ui-bootstrap-tpls文件中的单个特定模板。绝大部分默认模板都符合我的需求,但有几个特定的模板我想替换掉,而不用经过获取所有默认模板并将它们连接到非-tpls版本的整个过程。


1
我也发现自己装饰$modal服务以获得更多的可配置性,而不会(希望)创建太多的维护问题。 $provide.decorator('$modal'... 在我的情况下,我不想渲染modalWindow元素。从来没有。我只是没有使用它,这是我能想到的最好的方法。如果有人有更好的方法,我很乐意听听。 - bodine
4个回答

123

是的,来自http://angular-ui.github.io/bootstrap的指令高度可定制,很容易覆盖其中一个模板(同时仍依赖于其他指令的默认模板)。

只需向$templateCache提供内容,可以直接提供它(如在ui-bootstrap-tpls文件中所做的那样),或者更简单的方法是使用<script>指令覆盖模板(文档)。

下面是一个人为的例子,我将警报的模板更改为将x替换为关闭

<!doctype html>
<html ng-app="plunker">
  <head>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.4.0.js"></script>
    <script src="example.js"></script>
    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">

    <script id="template/alert/alert.html" type="text/ng-template">
      <div class='alert' ng-class='type && "alert-" + type'>
          <button ng-show='closeable' type='button' class='close' ng-click='close()'>Close</button>
          <div ng-transclude></div>
      </div>
    </script>
  </head>

  <body>
    <div ng-controller="AlertDemoCtrl">
      <alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">                     
        {{alert.msg}}
      </alert>
      <button class='btn' ng-click="addAlert()">Add Alert</button>
    </div>
  </body>
</html>

实时示例: http://plnkr.co/edit/gyjVMBxa3fToYTFJtnij?p=preview


19
我喜欢这个答案,只是不喜欢它没有包含在Angular UI的文档页面中,让我花了很长时间才弄清楚如何显示一个简单的模态框。 - trivektor
2
@BruceBanner 文档和实际工作示例是 Angular UI 的两个最大缺点。该项目非常出色,但需要一些甜蜜温柔的开发者之爱。 - Robin van Baalen
1
@RobinvanBaalen 这是一个AngularJS的特性(不是Angular-UI),它已经在AngularJS官方文档中有所记录 - vikki
请查看@JcT关于$provide.decorator的回答,因为这是覆盖指令模板的Angular方式(在这种情况下是最好的方式)。而且这很容易。只需将模板添加/覆盖到$templateCache中并不是最佳实践。 - John Bernardsson
@John 我不确定你从哪里得到的 "这是 Angular 的方式(在这种情况下是最好的方式)" 和 "仅仅将模板添加/覆盖到 $templateCache 中并不是最佳实践",但作为 Angular UI 和 Angular 维护者之一,我可以向你保证,覆盖模板没有任何问题。除非您有特定的问题要分享... - pkozlowski.opensource
显示剩余2条评论

81

使用 $provide.decorator

使用$provide装饰指令避免直接涉及$templateCache的问题。

相反,按照通常的方式创建你的外部模板html文件,并使用任何你喜欢的名称,然后覆盖指令的templateUrl指向它即可。

angular.module('plunker', ['ui.bootstrap'])
  .config(['$provide', Decorate]);

  function Decorate($provide) {
    $provide.decorator('alertDirective', function($delegate) {
      var directive = $delegate[0];

      directive.templateUrl = "alertOverride.tpl.html";

      return $delegate;
    });
  }

这是 pkozlowski.opensource 的 plunkr 分支:http://plnkr.co/edit/RE9AvUwEmKmAzem9mfpI?p=preview

(请注意,您必须在要装饰的指令名称后附加“Directive”后缀。上面的示例中,我们正在装饰UI Bootstrap的alert指令,因此我们使用名称alertDirective。)

由于您可能经常想要做的不仅仅是覆盖templateUrl,因此这提供了一个良好的起点,可以进一步扩展指令,例如通过重写/包装链接或编译函数(例如)。


9
这是正确的解决方案,符合 Angular 最佳实践。你永远不应该使用字符串来创建 HTML,也不应该在 index.html 文件中显式地包含它,或者在其中注入第三方脚本。感谢 @JcT! - TommyMac
2
嗨,alertDirective 是一个关键字吗?如果是的话,Tabs 的关键字是什么?我正在尝试在标签页上做类似的事情,但我查看了 alert.js,并没有找到它们使用 alertDirective 的地方。 - codenamezero
4
当您注册指令时,angularjs的$compileProvider会在您的指令名称后面附加“Directive”后缀($filterProvider也会使用“Filter”后缀类似地操作);对于大多数情况,这是不可见的,但当您进行修饰时,您需要将此后缀添加到您想要定位的指令中。例如,tabDirectivetabsetDirective等等。我没有找到确切的清晰文档,但是这里至少有一个关于$filterProvider类似行为的参考链接:https://docs.angularjs.org/api/ng/provider/$filterProvider - JcT
2
非常感谢@JcT,你的回答很棒。这是正确的方法。正如你所说,这是“装饰”第三方指令的好起点 :) - John Bernardsson
1
@ValeraTumash: 抱歉回答晚了。是的,我认为您的配置将被覆盖;但是,从Angular v1.3开始,我相信您可以向templateUrl提供一个function(element, attributes)。您可以使用此功能进行一些动态行为(根据属性返回原始templateUrl函数或自己的url字符串等)。但是,ui.bootstrap现在也使用此相同的功能,让您在指令上提供一个template-url属性,因此如果您愿意通过指令元素属性直接提供模板路径,则也可能使用该功能。 - JcT
显示剩余5条评论

27

来自 pkozlowski.opensource 的回答非常有用,帮助了我很多!我在我的情况下进行了微调,以便使用单个文件定义所有的角度模板覆盖,并加载外部JS以减小负载大小。

要做到这一点,请转到angular ui-bootstrap源js文件的底部(例如:ui-bootstrap-tpls-0.6.0.js),找到您感兴趣的模板。复制定义模板的整个块并将其粘贴到您的覆盖JS文件中。

例如:

angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
  $templateCache.put("template/alert/alert.html",
     "      <div class='alert' ng-class='type && \"alert-\" + type'>\n" +
     "          <button ng-show='closeable' type='button' class='close' ng-click='close()'>Close</button>\n" +
     "          <div ng-transclude></div>\n" +
     "      </div>");
}]);
然后只需在ui-bootstrap之后包含您的覆盖文件,就可以实现相同的结果。 pkozlowski.opensource的plunk的分支版本http://plnkr.co/edit/iF5xw2YTrQ0IAalAYiAg?p=preview

1
我使用相同的模式,尽管它有效,但我真的希望有更好的方法。我认为我更喜欢配置而不是破坏。 - bodine

7
你可以使用template-url="/app/.../_something.template.html"来覆盖该指令的当前模板。 (至少在Accordion Bootstrap中有效。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接