2011-05-17 16 views
13

Utilizando el complemento prettyPhoto para abrir contenedores de contenido de estilo modal e intentando integrar con el seguimiento de eventos de Google Analytics para rastrear cuándo se abren los videos.jQuery vincular el detector de eventos antes que otro

El problema es que cuando me

$('a.videoClickListener').click(function(event){ 
    console.log('here'); 
    _gaq.push(['_trackEvent', 'Product Page', 'Video Open', '<?php echo $product->getNameWithManufacturer(); ?>']); 
}); 

el evento nunca se dispara, como PrettyPhoto detiene el caso de continuar (con razón, ya que de lo contrario la página cambiaría si un hipervínculo se ha hecho clic).

prettyPhoto no parece proporcionar una función de devolución de llamada 'abierta', pero si lo hiciera no podría usarlo de todos modos, ya que los escuchas de prettyPhoto están configurados en algún lugar del diseño (usamos rel="prettyPhoto" cada vez que queremos usar prettyPhoto, y pasa los parámetros a través de la URL, que es la forma recomendada por prettyPhoto de hacer las cosas). También me gustaría pasar los detalles del producto a Analytics, descartando a un oyente de apertura de video global en todos los eventos de apertura de prettyPhoto.

¿Cómo puedo vincular a mi oyente antes de el oyente prettyPhoto? Si resulta que tengo que usar .unbind(), enlazar mi oyente, y luego volver a enlazar prettyPhoto, ¿cómo puedo desvincular un controlador especificado en un complemento?

Respuesta

18

Idealmente, usted será capaz de añadir su suceso de unión antes de cualquier otro, de manera que éste se ejecuta primero.

Desafortunadamente, jQuery no parece incluir ninguna de estas facilidades.

Sin embargo, he codificado un preBind method, que parece hacer el truco:

$.fn.preBind = function(type, data, fn) { 
    this.bind(type, data, fn); 

    var currentBindings = this.data('events')[type]; 
    var currentBindingsLastIndex = currentBindings.length - 1; 

    var newBindings = []; 

    newBindings.push(currentBindings[currentBindingsLastIndex]); 

    $.each(currentBindings, function (index) { 
    if (index < currentBindingsLastIndex) 
     newBindings.push(this); 
    }); 

    this.data('events')[type] = newBindings; 

    return this; 
}; 

Uso:

$('#button').bind('click', function() { 
    console.log('world'); 
}); 

// 2nd apostrophe for the selector was missing 
$('#button').preBind('click', function() { 
    console.log('hello'); 
}); 

$('#button').click(); 

// Output: 
// 
// > "hello" 
// > "world" 
+0

Pruebe la siguiente solución para obtener los eventos en las versiones de jQuery más nuevas y más antiguas: stackoverflow.com/a/26892146/655224 – algorhythm

+0

TypeError no detectado: no se puede leer la propiedad 'change' de undefined (...) – fdrv

-1

si usa unbind(), incluso las vinculaciones creadas por los complementos se desvincularán.

+0

Gracias por la respuesta. ¿Cómo voy a seleccionar un evento para desvincular? ¿Se nombran de alguna manera? En prettyPhoto, el oyente está vinculado como una función anónima. – sennett

+1

¿cómo prettyphoto está deteniendo el evento? Si tanto usted como el complemento están escuchando algún tipo de evento en el mismo elemento, no hay forma de que el complemento pueda detener el disparo que usted realiza. Escuche el mismo tipo de evento que el plugin escucha y también escuche exactamente en el mismo elemento. – Amareswar

+0

Gracias una vez más. Parece que está funcionando ahora ... Debo haber cometido otro error en alguna parte (posiblemente sin codificar el nombre del producto al pasar a JavaScript desde PHP). – sennett

13

estoy usando el método preBind de Jonathan, con ligeras modificaciones, y lo hace el truco muy bien.

$.fn.preBind = function (type, data, fn) { 
    this.each(function() { 
     var $this = $(this); 

     $this.bind(type, data, fn); 

     var currentBindings = $this.data('events')[type]; 
     if ($.isArray(currentBindings)) { 
      currentBindings.unshift(currentBindings.pop()); 
     } 
    }); 
    return this; 
}; 
+0

+1: El código es una optimización isofuncional de jonathanconway's. – Adrien

+5

En las versiones más recientes de jQuery '$ this.data ('events') [type]' no funciona. Debe usar '$ ._ data (this, 'events') [type]' –

+0

@RichardRout Pruebe la siguiente solución para obtener los eventos en versiones de jQuery más nuevas y antiguas: http://stackoverflow.com/a/26892146/655224 – algorhythm

2

tuvo que cambiar una línea en el código anterior para hacer que funcione:

var currentBindings = $this.data('events',type); // var currentBindings = $this.data('events')[type]; 

Esto podría ser porque estoy usando jQuery 2.0.3

+1

En 1.8.3 tuve que usar lo siguiente: '' '$ ._ data (this," events ") [type];' ''. Tenga en cuenta que 'este' es el elemento html real y no un objeto jQuery. – Gowiem

6

a mí me funcionó con mayores y más recientes jQuery versiones:

/** 
* @link http://stackoverflow.com/a/26892146/655224 
*/ 
jQuery.fn.getEvents = function() { 
    if (typeof(jQuery._data) == 'function') { 
     return jQuery._data(this.get(0), 'events') || {}; 
    } else if (typeof(this.data) == 'function') { // jQuery version < 1.7.? 
     return this.data('events') || {}; 
    } 
    return {}; 
}; 

jQuery.fn.preBind = function(type, data, fn) { 
    this.each(function() { 
     var $this = jQuery(this); 

     $this.bind(type, data, fn); 

     var currentBindings = $this.getEvents()[type]; 
     if (jQuery.isArray(currentBindings)) { 
      currentBindings.unshift(currentBindings.pop()); 
     } 
    }); 
    return this; 
}; 

Pero ojo, esto funciona sólo pueden volver/prebind que los eventos que se configurado con jQuery.

Un agradecimiento especial a @jonathanconway y @Patrick ...

+0

Consulte también este hilo: http://stackoverflow.com/a/26892146/655224 – algorhythm

5

Aquí es una variante de la solución utilizando el enfoque más moderno .En().

// Same as .on() but moves the binding to the front of the queue. 
$.fn.priorityOn = function (type, selector, data, fn) { 
    this.each(function() { 
     var $this = $(this); 

     var types = type.split(" "); 

     for (var t in types) { 
      $this.on(types[t], selector, data, fn); 

      var currentBindings = $._data(this, 'events')[types[t]]; 
      if ($.isArray(currentBindings)) { 
       currentBindings.unshift(currentBindings.pop()); 
      } 
     } 


    }); 
    return this; 
}; 

El uso es como

$(document).priorityOn("click blur change", ".some .selector input", function (e) { 
    // Your code. 
}); 
Cuestiones relacionadas