Como posso adicionar dinamicamente uma diretiva no AngularJS?

Eu tenho uma versão muito resumida do que estou fazendo que resolve o problema.

Eu tenho uma directive simples. Sempre que você clica em um elemento, ele adiciona outro. No entanto, ele precisa ser compilado primeiro para processá-lo corretamente.

Minha pesquisa me levou a $compile . Mas todos os exemplos usam uma estrutura complicada que eu realmente não sei como aplicar aqui.

Os violinos estão aqui: http://jsfiddle.net/paulocoelho/fBjbP/1/

E o JS está aqui:

 var module = angular.module('testApp', []) .directive('test', function () { return { restrict: 'E', template: '

{{text}}

', scope: { text: '@text' }, link:function(scope,element){ $( element ).click(function(){ // TODO: This does not do what it's supposed to :( $(this).parent().append(""); }); } }; });

Solução de Josh David Miller: http://jsfiddle.net/paulocoelho/fBjbP/2/

   

Você tem um monte de jQuery sem sentido lá, mas o serviço $ compile é super simples nesse caso:

 .directive( 'test', function ( $compile ) { return { restrict: 'E', scope: { text: '@' }, template: '

{{text}}

', controller: function ( $scope, $element ) { $scope.add = function () { var el = $compile( "" )( $scope ); $element.parent().append( el ); }; } }; });

Você notará que eu refatorei sua diretiva também para seguir algumas práticas recomendadas. Deixe-me saber se você tem dúvidas sobre qualquer um desses.

Além de aperfeiçoar o exemplo da Riceball LEE de adicionar uma nova diretriz-elemento

 newElement = $compile("
")($scope) $element.parent().append(newElement)

Adicionar uma nova diretiva de atributo ao elemento existente poderia ser feito dessa maneira:

Digamos que você queira adicionar my-directive on-the-fly ao elemento span .

 template: '
Hello World
' link: ($scope, $element, $attrs) -> span = $element.find('span').clone() span.attr('my-directive', 'my-directive') span = $compile(span)($scope) $element.find('span').replaceWith span

Espero que ajude.

Adicionar diretivas dinamicamente no angularjs tem dois estilos:

Adicione uma diretiva angularjs em outra diretiva

  • inserindo um novo elemento (diretiva)
  • Inserindo um novo atributo (diretiva) no elemento

inserindo um novo elemento (diretiva)

é simples. E vc pode usar em “link” ou “compilar”.

 var newElement = $compile( "
" )( $scope ); $element.parent().append( newElement );

inserindo um novo atributo no elemento

É difícil e me causa dor de cabeça dentro de dois dias.

Usando “$ compile” irá gerar erro recursivo crítico !! Talvez deva ignorar a diretiva atual ao recompilar o elemento.

 $element.$set("myDirective", "expression"); var newElement = $compile( $element )( $scope ); // critical recursive error. var newElement = angular.copy(element); // the same error too. $element.replaceWith( newElement ); 

Então, eu tenho que encontrar uma maneira de chamar a function “link” da diretiva. É muito difícil conseguir os methods úteis que estão escondidos profundamente dentro dos fechamentos.

 compile: (tElement, tAttrs, transclude) -> links = [] myDirectiveLink = $injector.get('myDirective'+'Directive')[0] #this is the way links.push myDirectiveLink myAnotherDirectiveLink = ($scope, $element, attrs) -> #.... links.push myAnotherDirectiveLink return (scope, elm, attrs, ctrl) -> for link in links link(scope, elm, attrs, ctrl) 

Agora funciona bem.

 function addAttr(scope, el, attrName, attrValue) { el.replaceWith($compile(el.clone().attr(attrName, attrValue))(scope)); } 

A resposta aceita por Josh David Miller funciona muito bem se você está tentando adicionar dinamicamente uma diretiva que usa um template in-line. No entanto, se a sua diretiva aproveitar o templateUrl a resposta não funcionará. Aqui está o que funcionou para mim:

 .directive('helperModal', [, "$compile", "$timeout", function ($compile, $timeout) { return { restrict: 'E', replace: true, scope: {}, templateUrl: "app/views/modal.html", link: function (scope, element, attrs) { scope.modalTitle = attrs.modaltitle; scope.modalContentDirective = attrs.modalcontentdirective; }, controller: function ($scope, $element, $attrs) { if ($attrs.modalcontentdirective != undefined && $attrs.modalcontentdirective != '') { var el = $compile($attrs.modalcontentdirective)($scope); $timeout(function () { $scope.$digest(); $element.find('.modal-body').append(el); }, 0); } } } }]); 

Josh David Miller está correto.

PCoelho, Caso você esteja se perguntando o que $compile faz nos bastidores e como a saída HTML é gerada a partir da diretiva, por favor, dê uma olhada abaixo

O serviço $compile compila o fragment de HTML ( "< test text='n' >< / test >" ) que inclui a diretiva (“test” como um elemento) e produz uma function. Esta function pode então ser executada com um escopo para obter a “saída HTML de uma diretiva”.

 var compileFunction = $compile("< test text='n' > < / test >"); var HtmlOutputFromDirective = compileFunction($scope); 

Mais detalhes com exemplos de código completo aqui: http://www.learn-angularjs-apps-projects.com/AngularJs/dynamically-add-directives-in-angularjs

Inspirada em muitas das respostas anteriores, desenvolvi a seguinte diretiva “stroman”, que replaceá qualquer outra diretiva.

 app.directive('stroman', function($compile) { return { link: function(scope, el, attrName) { var newElem = angular.element('
'); // Copying all of the attributes for (let prop in attrName.$attr) { newElem.attr(prop, attrName[prop]); } el.replaceWith($compile(newElem)(scope)); // Replacing } }; });

Importante: Registre as diretivas que você deseja usar com restrict: 'C' . Como isso:

 app.directive('my-directive', function() { return { restrict: 'C', template: 'Hi there', }; }); 

Você pode usar assim:

  

Para conseguir esta:

 
Hi there

Protip. Se você não quiser usar diretivas baseadas em classs, altere '

' para algo que você gosta. Por exemplo, tem um atributo fixo que contém o nome da diretiva desejada em vez da class .