Can you override specific templates in AngularUI Bootstrap?

AngularjsAngular UiAngular Ui-Bootstrap

Angularjs Problem Overview


I'm curious if there's a way to override single, specific templates from the ui-bootstrap-tpls file. The vast majority of the default templates fit my needs, but there's a couple specific ones I'd like to replace without going through the whole process of grabbing all the default templates and getting them wired up to the non-tpls version.

Angularjs Solutions


Solution 1 - Angularjs

Yes, directives from http://angular-ui.github.io/bootstrap are highly customizable and it is easy to override one of the templates (and still rely on the default ones for other directives).

It is enough to feed $templateCache, either feeding it directly (as done in the ui-bootstrap-tpls file) or - probably simpler - override a template using the <script> directive (doc).

A contrived example where I'm changing alert's template to swap x for Close is shown below:

<!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>

Live plunker: http://plnkr.co/edit/gyjVMBxa3fToYTFJtnij?p=preview

Solution 2 - Angularjs

Using $provide.decorator

Using $provide to decorate the directive avoids the need to directly mess around with $templateCache.

Instead, create your external template html as you might normally, with whatever name you please, and then override the directive's templateUrl to point at it.

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

Fork of pkozlowski.opensource's plunkr: http://plnkr.co/edit/RE9AvUwEmKmAzem9mfpI?p=preview

(Note that you must append the 'Directive' suffix to the directive name you intend to decorate. Above, we're decorating UI Bootstrap's alert directive, so we use the name alertDirective.)

As you may often want to do more than just override the templateUrl, this provides a good starting point from which to further extend the directive, for example by overriding/wrapping the link or compile function (for example).

Solution 3 - Angularjs

The answer from pkozlowski.opensource is really useful and helped me out a lot! I tweaked it in my condition to have a single file defining all of my angular template overrides and loaded the external JS to keep payload size down.

To do this, go to the bottom of the angular ui-bootstrap source js file (e.g. ui-bootstrap-tpls-0.6.0.js) and find the template you are interested in. Copy the entire block that defines the template and paste it into your overrides JS file.

e.g.

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

Then just include your overrides file after ui-bootstrap and you achieve the same result.

Forked version of pkozlowski.opensource's plunk http://plnkr.co/edit/iF5xw2YTrQ0IAalAYiAg?p=preview

Solution 4 - Angularjs

You can use template-url="/app/.../_something.template.html" to override the current template for that directive.

(Works in Accordion Bootstrap at least.)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeremy PrivettView Question on Stackoverflow
Solution 1 - Angularjspkozlowski.opensourceView Answer on Stackoverflow
Solution 2 - AngularjsJcTView Answer on Stackoverflow
Solution 3 - AngularjsMatt ByrneView Answer on Stackoverflow
Solution 4 - AngularjscrimsonView Answer on Stackoverflow