Estoy tratando de averiguar por qué mi función dejó de funcionar después de cambiar el código html.

Tengo un div:

<div class="float">
<div class="box" data-speed="3" data-direction="X"><h1>Hola</h1></div>
<div class="box" data-speed="2" data-direction="X"><h1>chau</h1></div>
</div>

Y el código jquery:

$(function() {
    $('.box').moveIt();
});    
//move elements in different speeds
$.fn.moveIt = function () {
    var win = $(window);
    var it = $(this);
    var instances = [];

    $(this).each(function (){
        instances.push(new moveItItem($(this)));
    });

    $('.parallax').on('scroll', function() {
        instances.forEach(function(inst){
            var wrap = inst.el.parents('.float');
            var scrol = win.scrollTop()-wrap.offset().top;
            inst.update(scrol);
        });
    });

}

var moveItItem = function(el){
  this.el = $(el);
  this.speed = parseInt(this.el.attr('data-scroll-speed'));
  this.direction = this.el.attr('data-direction');
};

moveItItem.prototype.update = function(scrollTop){
    var pos = scrollTop / this.speed;
    this.el.css('transform', 'translate'+this.direction+'(' + -pos + 'px)');
};

Ok hasta aquí todo funciona, cuando me desplazo los elementos .box se traducen en consecuencia.

Pero ahora estoy tratando de modificar el html en la clase .float después de una llamada ajax

//after ajax
$.ajax({
    url: 'do_content.php'
}).done(function(result) {
    //result = <div class="box" data-speed="3" data-direction="X"><h1>Como estas?</h1></div>
    $('.float').html(result);
});

Luego, cuando volví a disparar el desplazamiento, la función parece estar rota y recibí este mensaje:

Uncaught TypeError: Cannot read property 'top' of undefined
    at http://localhost/ophelia/public/js/control.js?v=1487219951:197:45
    at Array.forEach (native)
    at HTMLDivElement.<anonymous> (http://localhost/ophelia/public/js/control.js?v=1487219951:195:13)
    at HTMLDivElement.dispatch (http://localhost/ophelia/public/utilities/jquery/jquery-3.1.1.min.js:3:10315)
    at HTMLDivElement.q.handle (http://localhost/ophelia/public/utilities/jquery/jquery-3.1.1.min.js:3:8342)

Entiendo que este mensaje aparece solo si cambio los elementos con la clase .box (Traté de cambiar solo el h1 y no se rompe pero quiero cambiar todo para cambiar también las velocidades)

¿Cómo puedo volver a disparar la función?

Traté de llamarlo nuevamente con $('.box').moveIt(); pero sigo recibiendo el mismo error

Sé que es una pregunta larga pero no encontré otra forma de explicar mi problema

1
Tomas Lucena 16 feb. 2017 a las 07:53

3 respuestas

La mejor respuesta

Como ya se señaló (pero quizás no tan claro), el problema es que adjuntas un controlador de eventos utilizando elementos existentes en la página en un momento determinado (creo que a la instances var). Luego los sustituye, pero su controlador ya está configurado en el elemento de desplazamiento para la clase .parallax y ya está registrado usando esa instancia de instances y así sucesivamente.

Una forma es reescribir su código utilizando métodos delegados.

De http://api.jquery.com/on/

Los controladores de eventos están vinculados solo a los elementos seleccionados actualmente; deben existir en el momento en que su código hace la llamada a .on ().

Los eventos delegados tienen la ventaja de que pueden procesar eventos de elementos descendientes que se agregan al documento en un momento posterior

Un enfoque de delegación de eventos adjunta un controlador de eventos a un solo elemento, el tbody, y el evento solo necesita subir un nivel (desde el tr hasta tbody):

 $( "#dataTable tbody" ).on( "click", "tr", function() {

  console.log( $( this ).text() );

});

Pero puede ser complejo, ya que debería reestructurar profundamente su código.

De lo contrario, podría volver a escribir su función de la siguiente manera (lo siento, no puedo hacer violines)

$(function() {
    $('.parallax').moveIt();
});  

//move elements in different speeds
$.fn.moveIt = function () {
    var win = $(window);
    var it = $(this);
//REMOVED
//var instances = [];


//    $(this).each(function (){
//        instances.push(new moveItItem($(this)));
//    });

    $(this).on('scroll', function() {
        $('.box').each(function(){
            var inst=new moveItItem($(this));
            var wrap = inst.el.parents('.float');
            var scrol = win.scrollTop()-wrap.offset().top;
            inst.update(scrol);
        });
    });

 }

...... and so on
1
Massimo 16 feb. 2017 a las 06:06

Esto sucede porque el elemento html vinculado al oyente ha sido reemplazado. Al igual que en este fiddle aquí ... La alerta funciona, pero después de cambiar el html, no funciona. Esto se debe a que el elemento antiguo ha sido reemplazado por el nuevo elemento.

Puede usar la función on en jQuery para superar esto como en este fiddle

2
Prasun Jajodia 16 feb. 2017 a las 05:10

Puede vincular el evento en div.float y pasar por element.children para mover cada .box

1
troy 16 feb. 2017 a las 05:27