Você pode substituir modelos específicos no AngularUI Bootstrap?

88

Estou curioso para saber se há uma maneira de substituir modelos únicos e específicos do arquivo ui-bootstrap-tpls. A grande maioria dos modelos padrão atende às minhas necessidades, mas há alguns específicos que gostaria de substituir sem passar por todo o processo de pegar todos os modelos padrão e conectá-los à versão não tpls.

Jeremy Privett
fonte
1
Eu também me descobri decorando o $modalserviço para obter mais configurabilidade sem (espero) criar muita dor de cabeça de manutenção. $provide.decorator('$modal'... No meu caso, não queria renderizar o modalWindowelemento. Sempre. Eu simplesmente não estava usando, e isso foi o melhor que pude pensar. Eu adoraria ouvir uma maneira melhor, se alguém a tiver.
bodine

Respostas:

123

Sim, as diretivas de http://angular-ui.github.io/bootstrap são altamente personalizáveis ​​e é fácil substituir um dos modelos (e ainda contar com os padrões para outras diretivas).

É o suficiente para alimentar $templateCache, seja alimentando-o diretamente (como feito no ui-bootstrap-tplsarquivo) ou - provavelmente mais simples - sobrescrever um modelo usando a <script>diretiva ( doc ).

Um exemplo inventado onde eu estou mudando modelo de alerta para troca xde Closeé mostrado abaixo:

<!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 Live: http://plnkr.co/edit/gyjVMBxa3fToYTFJtnij?p=preview

pkozlowski.opensource
fonte
19
Eu gosto dessa resposta. Só não gosto do fato de não estar incluído na página de documentações da UI Angular e demorei um pouco para descobrir como fazer algo tão simples quanto mostrar um modal.
Tri Vuong
2
A documentação do @BruceBanner e exemplos de trabalho sólidos são as duas maiores quedas da IU Angular. O projeto é ótimo, mas precisa de um doce amor de desenvolvedor.
Robin van Baalen,
1
@RobinvanBaalen este é um recurso do angular-js (não angular-ui), já está documentado nos documentos oficiais do angular js
vikki
Por favor, verifique a resposta @JcT sobre $ supply.decorator, já que essa é a maneira Angular (a boa maneira neste caso) de sobrescrever modelos de diretiva. E é bastante fácil. Apenas adicionar / sobrescrever um template para $ templateCache não é realmente a melhor prática.
John Bernardsson
@John, não tenho certeza de onde você consegue as coisas "esse é o jeito Angular (o bom nesse caso)" e "apenas adicionar / sobrescrever um template para $ templateCache não é realmente a melhor prática", mas como um dos angulares- ui e mantenedores angulares, posso garantir que não há nada de errado em substituir os modelos. A menos que você tenha problemas específicos para compartilhar ...
pkozlowski.opensource
79

Usando $provide.decorator

Usar $providepara decorar a diretiva evita a necessidade de mexer diretamente com ela $templateCache.

Em vez disso, crie seu html de template externo como faria normalmente, com o nome que desejar, e então sobrescreva a diretiva templateUrlpara apontar para ele.

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

Bifurcação do plunkr de pkozlowski.opensource: http://plnkr.co/edit/RE9AvUwEmKmAzem9mfpI?p=preview

(Observe que você deve anexar o sufixo 'Diretiva' ao nome da diretiva que pretende decorar. Acima, estamos decorando a alertdiretiva do UI Bootstrap , por isso usamos o nome alertDirective.)

Como muitas vezes você pode querer fazer mais do que apenas substituir o templateUrl, isso fornece um bom ponto de partida para estender ainda mais a diretiva, por exemplo, substituindo / agrupando o link ou a função de compilação ( por exemplo ).

JcT
fonte
9
Esta é a solução correta e segue as melhores práticas angulares. Você NUNCA deve usar strings para criar HTML, nem deve incluir explicitamente no arquivo index.html onde você injeta scripts de terceiros. Obrigado @JcT!
TommyMac
2
Olá, é alertDirectiveuma palavra-chave? em caso afirmativo, para que serve a palavra-chave Tabs? Estou tentando fazer algo semelhante em guias, mas olhei em alert.js e não vejo onde eles estavam alertDirectivelá.
codenamezero
4
O angularjs $compileProvideranexa um sufixo 'Diretiva' ao nome de sua diretiva quando você a registra (o $filterProviderfaz de forma semelhante com um sufixo 'Filtro'); para a maioria dos propósitos, isso é invisível, mas ao decorar, você precisará anexar esse sufixo à diretiva que pretende atingir. Por exemplo, tabDirectiveou tabsetDirective, etc. Não exatamente claramente documentada em qualquer lugar que eu poderia encontrar, mas aqui é uma referência para o comportamento semelhante para $filterProvider, pelo menos: docs.angularjs.org/api/ng/provider/$filterProvider
JCT
2
Muito obrigado @JcT, uma ótima resposta. Este é o caminho correto a seguir. E, como você disse, um bom ponto de partida para "decoração" de diretivas de terceiros :)
John Bernardsson
1
@ValeraTumash: Desculpe pela resposta tardia. Sim, acho que sua configuração será superada; no entanto, a partir do Angular v1.3, acredito que você pode fornecer um function(element, attributes)para templateUrl. Você pode usar isso para algum comportamento dinâmico (retornar a função templateUrl original ou sua própria string de url dependendo de um atributo, etc). No entanto, ui.bootstrap agora também usa essa mesma funcionalidade para permitir que você forneça um template-urlatributo em uma diretiva, então você também pode potencialmente usar isso se estiver satisfeito em fornecer o caminho do modelo diretamente por meio do atributo do elemento de diretiva.
JcT
27

A resposta de pkozlowski.opensource é realmente útil e me ajudou muito! Eu alterei minha condição para ter um único arquivo definindo todas as minhas substituições de template angular e carreguei o JS externo para manter o tamanho da carga útil baixo.

Para fazer isso, vá para a parte inferior do arquivo js de origem ui-bootstrap angular (por exemplo ui-bootstrap-tpls-0.6.0.js) e encontre o modelo no qual está interessado. Copie todo o bloco que define o modelo e cole-o em seu arquivo JS de substituição.

por exemplo

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

Em seguida, apenas inclua seu arquivo de substituições após o ui-bootstrap e você obterá o mesmo resultado.

Versão bifurcada de pkozlowski.opensource 's plunk http://plnkr.co/edit/iF5xw2YTrQ0IAalAYiAg?p=preview

Matt Byrne
fonte
1
Eu uso o mesmo padrão, e embora funcione; Eu realmente gostaria que houvesse uma maneira melhor. Eu acho que preferiria configuração a vencer.
bodine
7

Você pode usar template-url="/app/.../_something.template.html"para substituir o modelo atual para essa diretiva.

(Funciona no Accordion Bootstrap, pelo menos.)

carmesim
fonte