personalizadas - directivas angularjs
¿Cómo puedo agregar dinámicamente una directiva en AngularJS? (7)
Tengo una versión muy resumida de lo que estoy haciendo que me permite solucionar el problema.
Tengo una directive
simple. Cada vez que haces clic en un elemento, agrega otro. Sin embargo, debe compilarse primero para representarlo correctamente.
Mi investigación me llevó a $compile
. Pero todos los ejemplos utilizan una estructura complicada que realmente no sé cómo aplicar aquí.
Los violines están aquí: http://jsfiddle.net/paulocoelho/fBjbP/1/
Y el JS está 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/
Además del perfecto ejemplo de Riceball LEE de agregar un nuevo elemento-directiva
newElement = $compile("<div my-directive=''n''></div>")($scope)
$element.parent().append(newElement)
Agregar una nueva directiva de atributo a un elemento existente podría hacerse de esta manera:
Digamos que desea agregar la my-directive
sobre la marcha 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 ayude.
Inspirado en muchas de las respuestas anteriores, se me ocurrió la siguiente directiva "stroman" que se reemplazará a sí misma con 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 usar con restrict: ''C''
. Me gusta esto:
app.directive(''my-directive'', function() {
return {
restrict: ''C'',
template: ''Hi there'',
};
});
Se puede 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 desea utilizar directivas basadas en clases, puede cambiar ''<div></div>''
a algo que desee. Por ejemplo, tener un atributo fijo que contenga el nombre de la directiva deseada en lugar de la class
.
Josh David Miller tiene razón.
PCoelho, en caso de que se esté preguntando qué hace $compile
detrás de la escena y cómo se genera la salida HTML 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 puede ejecutarse con un alcance para obtener el "resultado 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
La adición dinámica de directivas en angularjs tiene dos estilos:
Añadir una directiva angularjs en otra directiva
- insertando un nuevo elemento (directiva)
- Insertando un nuevo atributo (directiva) al elemento.
insertando un nuevo elemento (directiva)
es sencillo. Y u puede utilizar en "enlace" o "compilar".
var newElement = $compile( "<div my-diretive=''n''></div>" )( $scope );
$element.parent().append( newElement );
insertando un nuevo atributo al elemento
Es difícil, y me dan dolor de cabeza dentro de dos días.
¡Usar "$ compile" generará un error recursivo crítico! Tal vez debería ignorar la directiva actual al volver a compilar el 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 función de directiva "enlace". 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.
La respuesta aceptada de Josh David Miller funciona muy bien si está intentando agregar dinámicamente una directiva que usa una template
línea. 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);
}
}
}
}]);
Tienes un montón de jQuery sin sentido allí, pero el servicio $ compile es realmente muy 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á que también he reformulado su directiva para seguir algunas de las mejores prácticas. Déjame saber si tienes preguntas sobre cualquiera de esos.
function addAttr(scope, el, attrName, attrValue) {
el.replaceWith($compile(el.clone().attr(attrName, attrValue))(scope));
}