En este artículo vamos a hablar sobre AngularJS. En específico, vamos a ver el uso de directivas personalizadas y la aplicación de la directiva ui-sref la cual es muy utilizada en conjunto con las etiquetas <a> HTML para generar enlaces.
Usualmente cuando utilizamos ui-sref no pensamos en deshabilitar el click al elemento pues justamente ui-sref nos sirve para indicar la creación de un enlace a partir de un estado de las rutas. No obstante, existen casos en que queremos deshabilitar esta redirección en caso se cumpla cierta condición. Si es que han estado en una situación similar y han probado deshabilitando ui-sref de alguna forma, se podrán haber dado cuenta de que esto no es posible pues ui-sref ignora por completo cualquier intento de deshabilitarlo.
Por ejemplo, supongamos que tenemos lo siguiente:
<ul> <li ng-repeat="contact in contacts"> <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a> </li> </ul>
Es decir, estamos generando un enlace al detalle de los contactos mediante ui-sref y la función contacts.detail. ¿Pero que pasa si intentamos deshabilitar aquél enlace? Por ejemplo, podríamos intentar vinculando el evento “click” a una función vacía para así evitar que se ejecute ui-sref. Sin embargo, nos vamos a dar cuenta de que no funciona:
<ul> <li ng-repeat="contact in contacts"> <a ui-sref="contacts.detail({ id: contact.id })" ng-click="false">{{ contact.name }}</a> </li> </ul>
Esto no funcionará.
Podríamos probar de la siguiente forma también, dando como valor resultante false al llamado de ui-sref:
<ul> <li ng-repeat="contact in contacts"> <a ui-sref="false && contacts.detail({ id: contact.id })">{{ contact.name }}</a> </li> </ul>
Sin embargo, tampoco funcionará.
¿Entonces, cómo podemos prevenir el click en ui-sref con AngularJS de manera condicional? La respuesta está en el uso de directivas personalizadas. Lo que haremos, es declarar nuestra propia directiva encargada de “comer” el click en cualquier elemento, de tal manera que si el elemento tiene aquella directiva, ningún click funcionará sobre la misma.
La directiva que vamos a declarar es la siguiente:
module.directive('eatClickIf', ['$parse', '$rootScope',
function($parse, $rootScope) {
return {
// this ensure eatClickIf be compiled before ngClick
priority: 100,
restrict: 'A',
compile: function($element, attr) {
var fn = $parse(attr.eatClickIf);
return {
pre: function link(scope, element) {
var eventName = 'click';
element.on(eventName, function(event) {
var callback = function() {
if (fn(scope, {$event: event})) {
// prevents ng-click to be executed
event.stopImmediatePropagation();
// prevents href
event.preventDefault();
return false;
}
};
if ($rootScope.$phase) {
scope.$evalAsync(callback);
} else {
scope.$apply(callback);
}
});
},
post: function() {}
}
}
}
}
]);
El autor de dicha directiva es rnd y se puede encontrar originalmente en el siguiente enlace: Click acá
Una vez que insertemos dicha directiva, podemos hacer uso de la misma de la siguiente forma:
<ul> <li ng-repeat="contact in contacts"> <a eat-click-if="true" ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a> </li> </ul>
Con esto, “comeremos” el click realizado en la etiqueta <a> HTML si es que la condición pasada como parámetro es “true” como resultado y así evitaremos que se ejecute ui-sref por completo.