Ajax y JS, retraso extraño

eXtreM3

Buenas, quiero hacer una consulta por aquí, a modo de curiosidad. El código que tengo funciona, pero originalmente fallaba y no sé por qué.

Hago una petición normal por ajax a una serie de datos, los cuales, al ser recibidos, los inserto por filas en una tabla. El código original es el siguiente:

$.ajax({
  url: url_de_datos,
  dataType: 'json',
  success: function( response ) {
    $("#historytable tbody").empty();
    var tableData = response;
      $.each(tableData, function(k, v) {
        $("#historytable tbody").append("<tr><td>"+v.username+"</td><td title='a las "+v.hour+"'>"+v.day+"</td><td>"+v.description+"</td></tr>");
      });
  }
});

Aparentemente es correcto, pero creo que "lo hace tan rápido" que la tabla sigue vacía :\ , sin embargo, si meto ese each con un setTimeout sí que funciona

$.ajax({
  url: url_de_datos,
  dataType: 'json',
  success: function( response ) {
    $("#historytable tbody").empty();
    var tableData = response;
    setTimeout(function(){
      $.each(tableData, function(k, v) {
        $("#historytable tbody").append("<tr><td>"+v.username+"</td><td title='a las "+v.hour+"'>"+v.day+"</td><td>"+v.description+"</td></tr>");
      });
    },100);
  }
});

Por qué ocurre esto? o es que tengo incompleto el código 1?

S

El problema no parece que venga del código que pegas, o no existe #historytable cuando insertas el contenido u otra cosa lo esta quitando.

1 respuesta
B

Si se ejecuta al cargar la página ponla en el evento .ready para estar seguro que todos los elementos de la página están cargados.

2 respuestas
eXtreM3

#2 #historytable existe, se crea por html en la vista, existe antes de hacer clic en el botón que llama a ese ajax.

#3 el problema puede ser por el dom.ready? O sea, pensaba que en el ready se ponían las acciones que quisieras realizar después de que todo haya sido cargado. En este caso lo tengo en un function($) porque el código se ejecuta después:

  • La página carga (con el #historytable incluido)
  • Pulso un botón que carga el historial de un elemento (llamada ajax)
  • Inserto los datos en la tabla.

Jamás se me hubiese ocurrido que en este caso el problema era del dom ready. Entonces... ¿por qué si añado un settimeout de 100ms (también funciona si pongo 1ms) sí se ejecuta correctamente?

1 respuesta
S

#4 Si lo haces pulsando un boton el ready no tiene nada que ver, como ya te dice #3

Mi consejo es que pongas un breakpoint dentro del $.each y veas lo que esta pasando. Para saber por que te funciona el timeout te recomiendo leer algo sobre el event loop de javascript.

Según lo que cuentas podrías estar borrando el contenido justo después de insertarlo.

2 respuestas
B

#5 Hombre en #1 no especificaba si era un evento de botón o no por eso lo comentaba.

Por casualidad, cómo estás llamando al evento del botón?.

1 respuesta
eXtreM3

#5 no borro el contenido después de insertarlo, de hecho también he probado a comentar ese "empty" que tengo ahí por si acaso fuese eso, pero no.

#6

$( "#mi_boton" ).on( "click", function() {
      //ajax
});

edit: metiendo las funciones en el dom ready tampoco funciona, sólo funciona si dejo el setTimeout :( eso tiene que estar mal por cojones, es decir, debería funcionar de manera natural y no obligándolo a hacer un delay... es raro y no sé por qué. Lo malo es que es una intranet y no puedo rularos enlace para que lo veais... si tengo tiempo intento reproducir una copia en algún sitio de libre acceso.

1 respuesta
B

#7 usa


$(document).on( "click",'#mi_boton', function(event) {
      //ajax
});

1 1 respuesta
eXtreM3

#8 solucionado! xD (sin pasar event como parámetro), cuál es la diferencia entre mi #7 y tu #8 ?

Adiós setTimeout adiós :D

1 respuesta
B

#9 No he visto todo el código pero básicamente cuando estás trabajando con elementos dinámicamente(borrando, creando, etc) es mejor delegar el evento al documento y no directamente al elemento.

1 respuesta
eXtreM3

#10 interesante, puede que eso me solucione problemas que he tenido otras veces, que he tenido que bindear y unbindear eventos...


chapando!

Foxandxss

#1 Por decirlo de forma sencilla y sin enrollarme, con el setTimeout lo que estás haciendo es algo en plan: Oye navegador, te dejo que termines de renderizar tu html y luego ejecuta este codigo.

Es un truco muy viejo y común para cuando necesitas hacer algo y el dom no está listo.

JuAn4k4

No bindees muchas cosas a document, intenta bindearlas a cosas que esten en la página que no cambien (contexto).

Intenta cachear objetos, sobre todo jquery fuera de los bucles, por ej:

$("#historytable tbody")

La diferencia entre bindear al document y a tu objeto es:

a) "Busca un objeto #mi_boton ahora, y cuando hagan click en él, haz esto."
vs
b) "Busca el objeto document y cuando dentro de el, se haga click en un elemento #mi_boton, haz esto."

Si despues de a) borras #mi_boton y lo vuelves a poner, este nuevo no tiene el evento asignado.

Usuarios habituales