0

Tengo la siguiente llamada ajax

var listaTurnos = []
  $(document).ready(function() {
    $.ajax({
        type: 'POST',
        url: 'ajax/turnos2.ajax.php',
        dataType: "json",
        data: { item: "a" },
        success: function(data) {
            data.forEach(e => {
                listaTurnos.push(e["datos"])
            });
        },
        error: function(data) {
        }
    });
});

La cosa es que no entiendo el tema de la asincronia de ajax, porque si yo tiro un console.log(listaTurnos) recibo lo siguiente:

[]
0: "{"title":"Agustin Guerra","start":"2020-03-12T10:30:00","end":"2020-03-12T11:30:00"}
↵"
1: "{"title":"Mariel Guerrieri","start":"2020-03-15T09:30:00","end":"2020-03-15T10:30:00"}
↵"
length: 2
__proto__: Array(0)

Pero si yo en cambio pusiera

console.log(listaTurnos.length)

El resultado de la consola es 0.

>En un principio yo realice esta pregunta para saber cómo recorrer un objeto. Lo extraño es que otras veces he logrado hacerlo, y ahora no funcionaba. Preguntando por ahi me dijeron que ajax como es asincronico, en momentos va a cargar mi variable y en otros no. Quisiera poder manejar eso

Este era mi objetivo principal, pero ahora la idea es entender cuando ajax hace lo que hace y porque

Quisiera, a partir de este objeto, obtener un string que sea:

[
    {
        title: 'Agustin Guerra',
        start: '2020-03-12T10:30:00',
        end: '2020-03-12T11:30:00'
    },
    {
        title: 'Mariel Guerrieri',
        start: '2020-03-15T09:30:00',
        end: '2020-03-15T10:30:00'
    }

]

Intento recorrer con un foreach por ejemplo

   listaTurnos.forEach(e => {
    console.log(e)
});

Y no retorna nada. Yo quisiera recorrerlo para obtener al menos sus elementos de la forma {"title":"Agustin Guerra","start":"2020-03-12T10:30:00","end":"2020-03-12T11:30:00"} y despues trabajarlos con algun metodo de reemplazo de caracteres para llegar a mi objetivo. La cosa es que no estoy dandome cuenta de que método utilizar para iterar el objeto.

EDIT: dentro del success de ajax, si hago console.log(data) obtengo

(2) [{…}, {…}]
0: {id: "1", datos: "{"title":"Agustin Guerra","start":"2020-03-12T10:30:00","end":"2020-03-12T11:30:00"}
↵"}
1: {id: "2", datos: "{"title":"Mariel Guerrieri","start":"2020-03-15T09:30:00","end":"2020-03-15T10:30:00"}
↵"}
Agustin G.
  • 1,946
  • 8
  • 25

2 Answers2

1

no entiendo muy bien que es lo que quieres hacer. Dices que quieres un string con esa estrucutra, pero ya la tienes. O solo quieres mostrarlo con ese formato? Si quieres imprimir tu arreglo de objetos en ese formato puedes usar

const formato = JSON.stringify(arr, null, 2);
console.log(formato);
// te genera este string
[
    {
        title: 'Agustin Guerra',
        start: '2020-03-12T10:30:00',
        end: '2020-03-12T11:30:00'
    },
    {
        title: 'Mariel Guerrieri',
        start: '2020-03-15T09:30:00',
        end: '2020-03-15T10:30:00'
    }

]

Eso le daria el formato que quieres a tu arreglo.

Pero si quieres iterar los objetos y usar sus propiedades dentro del arreglo podrias usar un for..of

for(let item of listaTurnos) {
  console.log(item.title);
  console.log(item.start)
  // etc etc
}

O el mismo forEach que estas utlizado

   listaTurnos.forEach(e => {
    console.log(e.title)
   // etc
});
Isaac
  • 1,063
  • 2
  • 7
  • 15
  • Intenté las tres maneras que me decis, en el primer caso si le paso ``JSON.stringify`` me retorna ``[]``, completamente vacio. – Agustin G. Mar 16 '20 at 03:16
  • En los otros dos casos directamente no retorna nada. Yo quisiera al menos poder acceder al objeto para extraer las cadenas ``{"title":"Agustin Guerra","start":"2020-03-12T10:30:00","end":"2020-03-12T11:30:00"}`` – Agustin G. Mar 16 '20 at 03:17
  • Me preguntas que quiero hacer: Yo estoy obteniendo el objeto ``listaTurnos`` desde la base datos a traves de ``ajax``. Una vez que lo recibi, necesito crear una cadena como indico en la pregunta, a partir de este objeto. Para eso necesito poder accederlo y extraerle los valores, pero no entiendo porque no estoy pudiendo recorrerlo, ni con ``for`` ni con ``for..in`` ni con ``forEach`` – Agustin G. Mar 16 '20 at 03:22
  • Ooooh okay, y tú Ajax como lo estás haciendo, ya verificaste que si está regresando algo del request? – Isaac Mar 16 '20 at 04:46
1

Nueva respuesta

Las peticiones a Ajax son asíncronas. En pocas palabras significa que cuando se lanza una petición Ajax, Javascript abre un hilo aparte para procesar esa petición y no bloquear la interfaz del usuario (otras cosas pueden seguir sucediendo mientras la petición es procesada).

Cuando la petición termina, en la pila de llamadas de Javascript se registra una función con el resultado de esa petición. Es por ese motivo por el que no puedes asignar directamente los resultados de la petición Ajax a una variable pre-existente. Tendrías que agregar un callback (otra función) para que la función que registre Ajax cuando termine le pase los datos.

Este es uno de los rompecabezas que vienen a resolver las Promesas en Javascript. Y jQuery, a través de done 1 implementa una especie de Promesa (llamada Deferred), por lo que puedes fácilmente pasar datos de la petición a otra función de forma relativamente fácil.

Veamos un ejemplo:

$(function() { /*Esto sustituye a document.ready, obsoleto de jQuery 3*/
  var listaTurnos = [];
    /*
       Para que se vea más claro 
       crearemos primero una referencia a Ajaz
       y luego le agregaremos las funciones
    */
    var mAjax = $.ajax({
      url: 'ajax/turnos2.ajax.php',
      method: 'POST',
      data: { item: "a" },
      dataType: 'json' 
    });
    /*
       Cuando la petición termine se registrará done
       y cuando se registre done invocará 
       a readData pasándole la respuesta
    */
    mAjax.done(function(data) {
      /*data puede usarse aquí si se quiere*/
      readData(data);
    });
    /*
        Conviene otorgar también función fail a nuestras peticiones Ajax
        Aquí se controlará la respuesta cuando ésta falle
        OJO: aquí fail se refiere a fallos de red u otros, no a fallos de lógica
    */

    mAjax.fail(function(jqXHR, textStatus) {
      alert("Error en la petición: " + textStatus);
    });

  /*
     Función que sirve como callback
  */
  function readData(data) {
    /*
      La lectura siempre depende de cómo estén
      estructurados los datos
    */
    data.datos.forEach(e => {
      listaTurnos.push(e)
    });
    console.log(listaTurnos);
  }

});

Prueba

Hagamos una prueba funcional, con un código parecido al tuyo:

$(function() { /*Esto sustituye a document.ready, obsoleto de jQuery 3*/
  var listaTurnos = [];
    /*
       Para que se vea más claro 
       crearemos primero una referencia a Ajaz
       y luego le agregaremos las funciones
    */
    var mAjax = $.ajax({
      url: 'http://openlibrary.org/books/OL1M/lists.json',
      method: 'GET',
      /*data: { item: "a" },*/
      dataType: 'json' 
    });
    /*
       Cuando la petición termine se registrará done
       y cuando se registre done invocará 
       a readData pasándole la respuesta
    */
    mAjax.done(function(data) {
      /*data puede usarse aquí si se quiere*/
      readData(data);
    });
    /*
     Conviene otorgar también función fail a nuestras peticiones Ajax
     Aquí se controlará la respuesta cuando ésta falle
     OJO: aquí fail se refiere a fallos de red u otros, no a fallos de lógica
    */

    mAjax.fail(function(jqXHR, textStatus) {
      alert("Error en la petición: " + textStatus);
    });


  function readData(data) {
    data.entries.forEach(e => {
      listaTurnos.push(e)
    });
    console.log(listaTurnos);
  }

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Notas

  1. Aprovecho para decir que tanto document.ready con success y error se consideran ya obsoletos. Se recomienda cambiarlos por fuction, done y fail respectivamente, como se ha hecho en el código de ejemplo.

@deprected

El problema parece ser que tu objeto no es un JSON válido. Un JSON válido debe tener las claves y valores entre comillas dobles, por ejemplo: "title" : "Agustin...", esto no es válido: title: "Agustin...", esto tampoco: 'title':'Agustin'.

Veamos que tu código funciona si el JSON fuese válido. No siempre es obligatorio parsear el JSON, por ejemplo en una respuesta Ajax donde has puesto dataType: 'json' si luego intentas parsear, dará error. En ese caso, puedes pasar a usar el JSON con tal si tener que usar JSON.parse(respuestaAjax)

var listaTurnos =
  `
[
    {
        "title": "Agustin Guerra",
        "start": "2020-03-12T10:30:00",
        "end": "2020-03-12T11:30:00"
    },
    {
        "title": "Mariel Guerrieri",
        "start": "2020-03-15T09:30:00",
        "end": "2020-03-15T10:30:00"
    }
]`;

/*
  Parseamos a JSON, si es necesario
  NO siempre lo es
*/
var mJson = JSON.parse(listaTurnos);


/* Tu código */

mJson.forEach(e => {
  console.log(e)
});

/* Imprimir cada objeto con forma k: value */
for (var [key, item] of Object.entries(mJson)) {
  for (var [k, v] of Object.entries(item)) {
    console.log(`${k}: ${v}`);
  }
}
A. Cedano
  • 86,578
  • 19
  • 122
  • 221
  • creo que mi problema viene de otro lado entonces, ahi edite la pregunta. Si luego del ajax yo hago ``console.log(listaTurnos)`` tengo el objeto que inicia la pregunta. Ahora, si en cambio, en lugar de sacar por consola ``listaTurnos`` lo hago con ``listaTurnos.length`` devuelve 0. Puede ser un tema de asincronia que no estoy manejando correctamente? – Agustin G. Mar 16 '20 at 11:47
  • @AgustinG. qué es lo que quieres hacer aquí: `data.forEach(e => { listaTurnos.push(e["datos"]) });` ahí tu objeto es `data` realmente, que sería el JSON que obtienes desde el servidor. Haciendo eso modificas la respuesta, la metes en `listaTurnos` y le pones una clave `datos`. Entonces, para leerla tendrás que buscar por esa clave `datos`. No entiendo mucho por qué modificar de nuevo la respuesta ¿? – A. Cedano Mar 16 '20 at 11:53
  • En esa parte mi intencion es cargar cada uno de los elementos de la respuesta a ``listaTurnos``, si yo reemplazo ``listaTurnos.push(e["datos"])`` por ``console.log(e)`` obtengo uno a uno los elementos que quiero. Yo los quiero pasar todos a la variable ``listaTurnos``. Ahi edité la pregunta, ya que creo que mi problema no es tanto iterar un objeto, mas bien es de ajax. Alguien me dijo (en ingles asi que entendi lo que pude) que las llamadas ajax no se ejecutan ordenadamente como el resto de las ordenes del codigo. – Agustin G. Mar 16 '20 at 11:59
  • Perdon, ``console.log(e)`` retorna un objeto con dos propiedades,``id`` y ``datos``, yo necesito esta ultima. Por eso ``array.push(e["datos"])`` – Agustin G. Mar 16 '20 at 12:02
  • Las llamadas Ajax son asíncronas, entonces si quieres pasar `data` fuera de Ajax tienes pasarlo vía una función desde dentro del `success`. De todos modos, no aparece una clave `datos` en la respuesta que muestras, por lo tanto esto no es válido: `e["datos"]` – A. Cedano Mar 16 '20 at 12:02
  • Agrega el objeto completo que muestra `console.log(data);` – A. Cedano Mar 16 '20 at 12:03
  • agregado al final de la pregunta – Agustin G. Mar 16 '20 at 12:06
  • [Continuemos el debate en el chat](https://chat.stackexchange.com/rooms/105607/discussion-between-a-cedano-and-agustin-g). – A. Cedano Mar 16 '20 at 12:11