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:
é simples. E vc pode usar em “link” ou “compilar”.
var newElement = $compile( "" )( $scope ); $element.parent().append( newElement );
É 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
.