Archivo de la etiqueta: Jquery

Por qué no devolver false en un controlador de evento en jQuery

[programación]

Durante mucho tiempo he abusado de devolver false en los controladores de eventos de jQuery.

Por ejemplo:

$( 'a.un-link' ).on( 'click',
  function ( oEvent ) {
    // Hacer algo aquí!

    return false;
  }
);

Ese return false; es equivalente a hacer:

oEvent.preventDefault();
oEvent.stopPropagation();

Mi impresión es que está haciendo demasiado, ya que es posible que queramos que el evento se propague a alguno de los contenedores superiores.

En la mayoría de casos lo único que estamos intentando es prevenir que al hacer click, se redireccione a la dirección en el href del enlace, y para eso con oEvent.preventDefault() sería suficiente. Es por eso que estoy siguiendo las siguientes pautas en mi código más reciente:

  • oEvent.preventDefault() al inicio del método.
  • No devolver nada.
$( 'a.some-link' ).on( 'click',
  function ( oEvent ) {
    oEvent.preventDefault();
    // Hacer algo aquí!
  }
);

Esto impedirá la redirección y permitirá a los controladores superiores tratar el evento.

Comprobar si existe un elemento con AngularJS y ejecutar una función solo si existe

[programación]

Esta es la situación: Queremos ejecutar un plugin de JQuery sobre un elemento que se crea dinámicamente con un ng-repeat dentro una plantilla de AngularJS. Es decir, no podemos inicializar el plugin hasta que se ha cargado la plantilla y se han creado los elementos.

Tenemos un controlador específico para dicha plantilla, por lo que realizando la comprobación aquí, solucionamos la primera parte del problema. Investigando un poco, veo que la solución más popular es asignar una directiva al ng-repeat, que detectará cuando se ejecute la última iteración y lanzará un evento para ser recogido por el controlador, y entonces ya podríamos ahí ejecutar el plugin.

En Stackoverflow tenemos un ejemplo de esta aproximación, y en Nodewiz.biz tenemos otro ejemplo muy similar.

El caso es que esta aproximación me parece tremendamente rebuscada, aunque no dudo que cumple con el espíritu de AngularJS. Mi aproximación es más sencilla, aunque sospecho que no es del todo correcta, y me gustaría mejorarla con el tiempo:

$scope.bTooltipsterExists = false;

$scope.$watch(
function(){
    if(angular.element('.tooltipster').length){
        $scope.bTooltipsterExists = true;
        return true;
    }

    return false;
},
function(){
    if($scope.bTooltipsterExists){
        $(".tooltipster").tooltipster({
            trigger: 'click',
            delay: 0
        });
    }
});

Básicamente tengo un $watch que lo que hace es observar una función. Esta función busca los elementos que se crearán con el ng-repeat y tendrán la clase .tooltipster. La segunda función es la que se ejecuta cuando hay un cambio en el valor devuelto por la primera función. Es decir, cuando la primera función pase de devolver false a devolver true, se ejecutará el plugin.

Añado una segunda comprobación con la variable $scope.bTooltipsterExists porque la primera vez que se ejecuta el $watch, como no tiene una variable de referencia anterior, siempre se ejecuta la segunda función, y con esto lo evitamos.