¿Cómo puedo agregar dinámicamente una directiva en AngularJS?
Tengo una versión muy reducida de lo que estoy haciendo que transmite el problema.
Tengo un simple directive
. Cada vez que hace clic en un elemento, agrega otro. Sin embargo, necesita ser compilado primero para renderizarlo correctamente.
Mi investigación me llevó a $compile
. Pero todos los ejemplos usan una estructura complicada que realmente no sé cómo aplicar aquí.
Los violines están aquí: http://jsfiddle.net/paulocoelho/fBjbP/1 /
Y la JS es aquí:
var module = angular.module('testApp', [])
.directive('test', function () {
return {
restrict: 'E',
template: '<p>{{text}}</p>',
scope: {
text: '@text'
},
link:function(scope,element){
$( element ).click(function(){
// TODO: This does not do what it's supposed to :(
$(this).parent().append("<test text='n'></test>");
});
}
};
});
Solución de Josh David Miller: http://jsfiddle.net/paulocoelho/fBjbP/2 /
7 answers
Tiene un montón de jQuery sin sentido, pero el servicio compile compile es en realidad super simple en este caso:
.directive( 'test', function ( $compile ) {
return {
restrict: 'E',
scope: { text: '@' },
template: '<p ng-click="add()">{{text}}</p>',
controller: function ( $scope, $element ) {
$scope.add = function () {
var el = $compile( "<test text='n'></test>" )( $scope );
$element.parent().append( el );
};
}
};
});
Notarán que refactoricé su directiva también para seguir algunas de las mejores prácticas. Hazme saber si tienes preguntas sobre alguno de esos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-07 18:51:22
Además del ejemplo perfecto de Riceball LEE de agregar un nuevo elemento -directiva
newElement = $compile("<div my-directive='n'></div>")($scope)
$element.parent().append(newElement)
Agregar un nuevo atributo -directiva al elemento existente podría hacerse de esta manera:
Digamos que desea agregar sobre la marcha my-directive
al elemento span
.
template: '<div>Hello <span>World</span></div>'
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 eso ayude.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-21 16:12:43
La adición dinámica de directivas en angularjs tiene dos estilos:
Añadir una directiva angularjs en otra directiva
- insertar un nuevo elemento (directiva)
- insertar un nuevo atributo (directiva) al elemento
Insertar un nuevo elemento (directiva)
Es simple. Y u puede utilizar en "enlace" o "compilar".
var newElement = $compile( "<div my-diretive='n'></div>" )( $scope );
$element.parent().append( newElement );
Insertar un nuevo atributo en el elemento
Es difícil, y me da dolor de cabeza en dos días.
Usando "compile compile" elevará el error recursivo crítico!! Tal vez debería ignorar la directiva actual al volver a compilar 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 );
Por lo tanto, tengo que encontrar una manera de llamar a la directiva "enlace" función. Es muy difícil obtener los métodos útiles que se ocultan profundamente dentro de los cierres.
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)
Ahora, funciona bien.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-16 09:28:53
function addAttr(scope, el, attrName, attrValue) {
el.replaceWith($compile(el.clone().attr(attrName, attrValue))(scope));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-30 22:19:42
La respuesta aceptada por Josh David Miller funciona muy bien si usted está tratando de agregar dinámicamente una directiva que utiliza un inline template
. Sin embargo, si su directiva se aprovecha de templateUrl
su respuesta no funcionará. Esto es lo que funcionó para mí:
.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);
}
}
}
}]);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-25 07:15:08
Josh David Miller tiene razón.
PCoelho, En caso de que se pregunte qué hace $compile
entre bastidores y cómo se genera la salida HTML a partir de la directiva, eche un vistazo a continuación
El servicio $compile
compila el fragmento de HTML("< test text='n' >< / test >"
) que incluye la directiva("test" como elemento) y produce una función. Esta función se puede ejecutar con un ámbito para obtener la "salida HTML de una directiva".
var compileFunction = $compile("< test text='n' > < / test >");
var HtmlOutputFromDirective = compileFunction($scope);
Más detalles con ejemplos de código completo aquí: http://www.learn-angularjs-apps-projects.com/AngularJs/dynamically-add-directives-in-angularjs
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-18 05:05:41
Inspirado en muchas de las respuestas anteriores, se me ocurrió la siguiente directiva "stroman" que se reemplazará por cualquier otra directiva.
app.directive('stroman', function($compile) {
return {
link: function(scope, el, attrName) {
var newElem = angular.element('<div></div>');
// Copying all of the attributes
for (let prop in attrName.$attr) {
newElem.attr(prop, attrName[prop]);
}
el.replaceWith($compile(newElem)(scope)); // Replacing
}
};
});
Importante: Registre las directivas que desea utilizar con restrict: 'C'
. Así:
app.directive('my-directive', function() {
return {
restrict: 'C',
template: 'Hi there',
};
});
Puedes usar así:
<stroman class="my-directive other-class" randomProperty="8"></stroman>
Para obtener esto:
<div class="my-directive other-class" randomProperty="8">Hi there</div>
Protip. Si no quieres usar directivas basadas en clases entonces puedes cambiar '<div></div>'
a algo que te guste. P. ej. tener una se corrigió el atributo que contiene el nombre de la directiva deseada en lugar de class
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-14 17:34:41