¿Puede anular plantillas específicas en AngularUI Bootstrap?

88

Tengo curiosidad por saber si hay una manera de anular plantillas únicas y específicas del archivo ui-bootstrap-tpls. La gran mayoría de las plantillas predeterminadas se ajustan a mis necesidades, pero hay algunas específicas que me gustaría reemplazar sin pasar por todo el proceso de tomar todas las plantillas predeterminadas y conectarlas a la versión que no es tpls.

Jeremy Privett
fuente
1
También me encontré decorando el $modalservicio para obtener más capacidad de configuración sin (con suerte) crear demasiado dolor de cabeza de mantenimiento. $provide.decorator('$modal'... En mi caso, no quería renderizar el modalWindowelemento. Siempre. Simplemente no lo estaba usando, y esto fue lo mejor que se me ocurrió. Me encantaría escuchar una mejor manera si alguien la tiene.
bodine

Respuestas:

123

Sí, las directivas de http://angular-ui.github.io/bootstrap son altamente personalizables y es fácil anular una de las plantillas (y aún confiar en las predeterminadas para otras directivas).

Es suficiente alimentarlo $templateCache, ya sea directamente (como se hace en el ui-bootstrap-tplsarchivo) o, probablemente más simple, anular una plantilla usando la <script>directiva ( doc ).

Un ejemplo contribuido donde estoy cambiando la plantilla de alerta a intercambio xpara Closeque se muestra a continuación:

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

Plunker en vivo: http://plnkr.co/edit/gyjVMBxa3fToYTFJtnij?p=preview

pkozlowski.opensource
fuente
19
Me gusta esta respuesta. Simplemente no me gusta el hecho de que no está incluido en la página de documentación de Angular UI y me tomó bastante tiempo descubrir cómo hacer algo tan simple como mostrar un modal.
Tri Vuong
2
@BruceBanner La documentación y los ejemplos de trabajo sólidos son las dos mayores desventajas de Angular UI. El proyecto es genial, pero necesita un dulce y tierno amor por parte de los desarrolladores.
Robin van Baalen
1
@RobinvanBaalen esta es una característica angular-js (no angular-ui), ya está documentada en los documentos oficiales de angular js
vikki
Verifique la respuesta de @JcT sobre $ provide.decorator, ya que esa es la forma angular (la buena forma en este caso) de anular las plantillas de directiva. Y es bastante fácil. Simplemente agregar / anular una plantilla a $ templateCache no es realmente la mejor práctica.
John Bernardsson
@John No estoy seguro de dónde se obtienen las cosas "esa es la forma angular (la buena forma en este caso)" y "simplemente agregar / anular una plantilla a $ templateCache no es realmente la mejor práctica", sino como una de angular- ui y mantenedores angulares les puedo asegurar que no hay nada de malo en anular las plantillas. A menos que tenga problemas específicos para compartir ...
pkozlowski.opensource
79

Utilizando $provide.decorator

Usar $providepara decorar la directiva evita la necesidad de jugar directamente con ella $templateCache.

En su lugar, cree su plantilla html externa como lo haría normalmente, con el nombre que desee, y luego anule las directivas templateUrlpara señalarlo.

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

Bifurcación del plunkr de pkozlowski.opensource: http://plnkr.co/edit/RE9AvUwEmKmAzem9mfpI?p=preview

(Tenga en cuenta que debe agregar el sufijo 'Directiva' al nombre de la directiva que desea decorar. Arriba, estamos decorando la alertdirectiva UI Bootstrap , por lo que usamos el nombre alertDirective).

Como a menudo puede querer hacer algo más que anular templateUrl, esto proporciona un buen punto de partida desde el cual extender aún más la directiva, por ejemplo, anulando / ajustando el enlace o la función de compilación ( por ejemplo ).

JcT
fuente
9
Esta es la solución correcta y sigue las mejores prácticas angulares. NUNCA debe usar cadenas para crear HTML, ni debe tener que incluirlo explícitamente en el archivo index.html donde inyecta scripts de terceros. ¡Gracias @JcT!
TommyMac
2
Hola, ¿es alertDirectiveuna palabra clave? Si es así, ¿para qué es la palabra clave Tabs? Estoy tratando de hacer algo similar en las pestañas, pero miré a través de alert.js y no veo dónde tenían alertDirectiveallí.
codenamezero
4
El angularjs $compileProvideradjunta un sufijo de 'Directiva' al nombre de su directiva cuando la registra (lo $filterProviderhace de manera similar con un sufijo de 'Filtro'); para la mayoría de los propósitos, esto es invisible, pero al decorar, deberá agregar este sufijo a la directiva a la que desea dirigirse. Por ejemplo, tabDirectiveo tabsetDirective, etc. No está claramente documentado en ningún lugar que pueda encontrar, pero aquí hay una referencia al comportamiento similar para $filterProvideral menos: docs.angularjs.org/api/ng/provider/$filterProvider
JcT
2
Muchas gracias @JcT, una gran respuesta. Ésta es la forma correcta de hacerlo. Y, como dices, un buen punto de partida para la "decoración" de las directivas de terceros :)
John Bernardsson
1
@ValeraTumash: Perdón por la respuesta tardía. Sí, creo que tu configuración se verá afectada; sin embargo, desde Angular v1.3, creo que puede proporcionar function(element, attributes)a templateUrl. Puede usar esto para algún comportamiento dinámico (devolver la función templateUrl original o su propia cadena de URL dependiendo de un atributo, etc.). Sin embargo, ui.bootstrap ahora también usa esta misma funcionalidad para permitirle proporcionar un template-urlatributo en una directiva, por lo que también podría usarlo si está dispuesto a proporcionar la ruta de la plantilla directamente a través del atributo del elemento de la directiva.
JcT
27

¡La respuesta de pkozlowski.opensource es realmente útil y me ayudó mucho! Lo modifiqué en mi condición para tener un solo archivo que defina todas mis anulaciones de plantilla angular y cargué el JS externo para mantener el tamaño de la carga útil bajo.

Para hacer esto, vaya a la parte inferior del archivo js fuente angular ui-bootstrap (por ejemplo ui-bootstrap-tpls-0.6.0.js) y busque la plantilla que le interesa. Copie el bloque completo que define la plantilla y péguelo en su archivo JS de anulaciones.

p.ej

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

Luego, simplemente incluya su archivo de anulaciones después de ui-bootstrap y obtendrá el mismo resultado.

Versión bifurcada del plunk de pkozlowski.opensource http://plnkr.co/edit/iF5xw2YTrQ0IAalAYiAg?p=preview

Matt Byrne
fuente
1
Utilizo este mismo patrón, y aunque funciona; Realmente desearía que hubiera una mejor manera. Creo que preferiría la configuración a la paliza.
Bodine
7

Puede utilizar template-url="/app/.../_something.template.html"para anular la plantilla actual para esa directiva.

(Funciona en Accordion Bootstrap al menos).

carmesí
fuente