Capítulos
Ejercicios

AJAX AJAX
Conversaciones asincrónicas

Luis Felipe Ramírez Varela
https://luis.ramirez.cl
luis@ramirez.cl
luisfel

Conocimiento requerido
  • html
  • php
  • sql
  • sql
  • jquery
  • wp

AJAX no es otro lenguaje de programación, sino un método de interacción entre el browser y el servidor sin recargar la página. Básicamente está diseñado para utilizar la API "XMLHttpRequest" de javascript integrada en el browser y generar una sensación de "software" al usuario con un proceso de requerimiento "por debajo" al servidor.

AJAX son las siglas de "Asynchronous JavaScript and XML" (javascript y XML asincronico) y probablemente sea la razón por la que nacieron tantas librerías de JavaScript, ya que cada browser, en la época oscura de los 4.0 y la transición, implementaba una manera distinta para esta acción y el código que había que generar tenía que considerar todos los posibles navegadores. jQuery es uno de los que prosperó al discriminar el browser en el que se ejecutaba la petición.

XML en el nombre AJAX es un decir, ya que si bien nació para poder interactuar con este formato (XML) y era la gran apuesta de la W3C y de Microsoft, actualmente se le da mayor uso con JSON como formato de los datos en comuncación ocupando los mismos recursos de la sub conexión que XMLHttpRequest realiza.

Alerta:
El método AJAX funciona solo contra los servicios http, https, data, por lo que consultando directo al browser, en local, por file, no se va a ejecutar. Si queremos probar en local necesitamos un servidor instalado en nuestro computador. (http://php.luisfel.com/#instalacion de servicios).

Objetivo del capítulo:
Entender y utilizar conversaciones AJAX con javascript.

El objeto XMLHttpRequest de javascript apareció a finales del siglo pasado cuando Microsoft lo incorporó como una API en su navegador Explorer 5 como parte de la tecnología DHTML (Dynamic HTML).

No fué hasta el 2006 que la W3C lo incorporara como un estandard y los navegadores modernos se apropiaran de él para hacer conversaciones asincrónicas con el servidor (AJAX).

Ejemplo:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'ruta/al/archivo.json', true);
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        alert(xhr.responseText);
    }
};
xhr.send();

Como vemos en el ejemplo, primero creamos un objeto instanciando la API, también necesitamos definir, al menos, la URL o ruta al archivo en el servidor con el que queremos conversar y el método que vamos a transmitir los datos, que en este ejemplo es GET. Si evaluamos los estados del nuevo objeto creado en la variable xhr con onreadystatechange, podemos evaluar la respuesta y si el estado está completo ("4") y no hay error en el status ("200"), entonces podemos utilizar el método responseText con los datos que respondió el servidor en nuestra página. Vamos por partes.

XMLHttpRequest

Lo primero es crear un objeto que va a utilizar la API de javascript "XMLHttpRequest" y sus métodos.

Ejemplo:
var xhr = new XMLHttpRequest();

Ahora que tenemos un objeto con los métodos del API en la variable xhr, podemos comenzar a interactuar con los métodos y pasar los valores necesarios para la conversación con el servidor.

open

El método open() permite definir los parámetros de la conversación que queremos generar. Ésta generalmente lleva dos valores: El método de la conversación (GET ó POST) y la URL del destino en el servidor. Aunque se pueden definir 3 más: si va a ser una conversación asincrónica (qué es el método predeterminado) o sincrónica, y si necesita usuario y clave para conectarse con el archivo en el servidor.

Ejemplo:
xhttp.open("GET", "ruta/productos.json",false,"usuario","clave");

En este ejemplo, aparte de traer un archivo .json, le dice que la conversación es sincrónica y manda usuario y clave para validarse en el servidor.

send

El método open() no envía los datos, define el tipo de conversación, por lo que siempre está conectado con el método send(), que es el encargado final de ejecutar la conversación.

Ejemplo:
xhr.send();

send data

Cómo buena parte de nuestras conversaciones AJAX pueden enviar datos que recogemos del usuario, para procesar en el servidor.

Ejemplo:
var data = JSON.stringify({
    nombre: 'John',
    apellido: 'Doe',
    email: 'jd@nn.cl'
});

xhr.send(data);

En este ejemplo preparamos la variable data con un objeto con datos, convertido en un JSON con la método de javascript stringify( ).

onreadystatechange

Como AJAX se ocupa para enviar y recibir datos del servidor, se suele definir sobre el mismo nuevo objeto creado de conversación, que hacer con los datos recibidos. El método onreadystatechange es el que se encarga de evaluar en qué estado está la conversación.

Aquí es muy útil entender 2 métodos que vienen con el objeto: readyState, que es el estado actual de la conversación y el status, que se refiere al tipo de respuesta entregado por el servidor y sobre el que se puede colgar nuestra programación .

Ejemplo:
if var xhr = new XMLHttpRequest();
xhr.open('GET', 'ruta/al/archivo.json', true);
xhr.onreadystatechange = function () {
    alert("El estado ha cambiado.");
};
xhr.send();

En este ejemplo, levantamos una ventana con el método alert() cada vez que el estado cambie.

readyState

Desde que creamos el nuevo objeto XMLHttpRequest, se está monitoreando su estado. Se maenjan 5 estados que se pueden evaluar:

Estados del objeto XMLHttpRequest
estado descripción
0 No se ha realizado una inicialización del objeto
1 Conection establecida con el servidor
2 Envío recibido
3 Procesando el requerimiento
4 Consulta terminada y la respuesta está lista

En función de estos estados se puede gatillar diferentes feedback y por supuesto, hacer el "debug" de nuestra porgramación cuando no funcione.

Ejemplo:
if var xhr = new XMLHttpRequest();
xhr.open('GET', 'ruta/al/archivo.json', true);
xhr.onreadystatechange = function () {
  (xhr.readyState === 0) {
    console.log('Estado 0: UNSENT - La solicitud no ha sido inicializada.');
  } else if (xhr.readyState === 1) {
    console.log('Estado 1: OPENED - Se ha llamado a open().');
  } else if (xhr.readyState === 2) {
    console.log('Estado 2: HEADERS_RECEIVED - Se ha recibido la cabecera de la respuesta.');
  } else if (xhr.readyState === 3) {
    console.log('Estado 3: LOADING - Se está descargando el cuerpo de la respuesta.');
  } else if (xhr.readyState === 4) {
    console.log('Estado 4: DONE - La operación ha terminado.');
    if (xhr.status === 200) {
      console.log('Respuesta exitosa:', JSON.parse(xhr.responseText));
    } else {
      console.error('Error: ' + xhr.status);
    }
  }
};
xhr.send();

En este ejemplo, escribimos en la consola cada vez que cambie el estado del objeto xhr. Esto bien podría ser un javascript que levanta mensajes o íconos del proceso de conversación para darle feedback al usuario. Una vez que el proceso está terminado y la respuesta es 200 o sea ok, muestra la respuesta responseText del servidor y además, cómo pedimos un JSON, lo parsea para poder utilizarlo como objeto en la alimentación de nuestro contenido.

status

Por otro lado tenemos el método status de la respuesta del servidor, ésta está amarrado al los códigos de respuesta HTTP.

códigos de respuesta HTTP
rango descripción
(100199 Respuestas informativas
200299 Respuestas satisfactorias
(300399) Redirecciones
(400499) Errores de los clientes
(500599) errores de los servidores
Ejemplo:
var xhr = new XMLHttpRequest();
xhr.open('POST', 'ruta/al/archivo.php', true);

xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) { // La solicitud ha terminado
    if (xhr.status === 200) {
      console.log('Estado 200: OK - La solicitud fue exitosa.');
      console.log('Respuesta:', JSON.parse(xhr.responseText));
    } else if (xhr.status === 201) {
      console.log('Estado 201: Created - El recurso fue creado con éxito.');
    } else if (xhr.status === 400) {
      console.log('Estado 400: Bad Request - La solicitud es inválida.');
    } else if (xhr.status === 401) {
      console.log('Estado 401: Unauthorized - La autenticación es necesaria.');
    } else if (xhr.status === 404) {
      console.log('Estado 404: Not Found - El recurso no fue encontrado.');
    } else if (xhr.status === 500) {
      console.log('Estado 500: Internal Server Error - Error en el servidor.');
    } else {
      console.log('Estado ' + xhr.status + ': Ocurrió un error inesperado.');
    }
  }
};
var data = JSON.stringify({
    nombre: 'Caperucita',
    apellido: 'Roja',
    email: 'caperuza@deferoz.cl'
});

xhr.send(data);
xhr.send();

En este ejemplo, enviamos los datos a un script de php y escribimos en la consola los casos clásicos de respuesta que nos puede dar el servidor o un gran génerico al final del bucle.

responseText

El contenido de responseText en XMLHttpRequest depende del tipo de datos que el servidor envía en la respuesta. El servidor puede enviar datos en diferentes formatos, y la cabecera de la respuesta "Content-Type" juega un papel crucial en la interpretación de esos datos.

tipo Texto

El texto plano otext/plain es el formato más simple. responseText contiene una cadena de texto sin formato.

Ideal para respuestas cortas, como mensajes de estado o respuestas donde no se requiere un formato estructurado.

Ejemplo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Texto Plano</title>
</head>
<body>
<h1>Texto Plano</h1>
<button id="loadPlainText">Cargar Texto Plano</button>
<pre id="destino"></pre>
<script>
        document.getElementById('loadPlainText').addEventListener('click', function() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'ruta/al/texto:plano.txt', true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    document.getElementById('destino').textContent = xhr.responseText;
                }
            };
            xhr.send();
        });
    </script>
</body>
</html>

En este caso, agregamos como contenido de texto en el objeto con id "destino" el contenido recibido en responseText.

tipo HTML

El tipo HTML (text/html) es donde responseText contiene un fragmento de HTML. Utilizado cuando el servidor envía como resultado HTML que puede ser inyectado directamente en el DOM de la página.

Ejemplo:
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML</title>
</head>
<body>
    <h1>HTML</h1>
    <button id="loadHTML">Cargar HTML</button>
    <div id="destino"></div>

    <script>
        document.getElementById('loadHTML').addEventListener('click', function() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'ruta/al/archivo.html', true); 
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    document.getElementById('destino').innerHTML = xhr.responseText;
                }
            };
            xhr.send();
        });
    </script>
</body>
</html>

En este ejemplo, se carga como contenido HTML interpretado con el método innerHTML en el objeto con el id "destino" el fragmento recibido en el método responseText

tipo XML

Los tipo XML (application/xml o text/xml) de responseText contiene datos en formato XML, aunque a menudo se usa más responseXML en lugar de responseTextpara parsear y trabajar con un documento XML.

Utilizado en aplicaciones que dependen de datos estructurados, como configuraciones o respuestas de servicios web SOAP.

Ejemplo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest con XML</title>
</head>
<body>
<h1>Selecciona un Usuario</h1>
<form>
  <label for="users">Usuarios:</label>
  <select id="users">
    <option value="">Cargando usuarios...</option>
  </select>
</form>
<script>
        document.addEventListener('DOMContentLoaded', function() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'ruta/al/archivo.xml', true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    var xmlDoc = xhr.responseXML; 
                    var users = xmlDoc.getElementsByTagName('user'); 
                    var select = document.getElementById('users');
                    select.innerHTML = '';

                    for (var i = 0; i < users.length; i++) {
                        var id = users[i].getElementsByTagName('id')[0].textContent;
                        var name = users[i].getElementsByTagName('name')[0].textContent;

                        var option = document.createElement('option');
                        option.value = id;
                        option.textContent = name;

                        select.appendChild(option);
                    }

                    if (users.length === 0) {
                        var noDataOption = document.createElement('option');
                        noDataOption.value = '';
                        noDataOption.textContent = 'No hay usuarios disponibles';
                        select.appendChild(noDataOption);
                    }
                } else if (xhr.readyState === 4 && xhr.status !== 200) {
                    var select = document.getElementById('users');
                    select.innerHTML = '<option value="">Error al cargar los usuarios</option>';
                }
            };

            xhr.send();
        });
    </script>
</body>
</html>

En este ejemplo, la respuesta XML se parsea con el objeto responseXML y después se recorre la estructura a partir de su TagName agregandolo como <option> del <select> con el id "users"

tipo JSON

Las respuestas tipo JSON (application/json)de responseText contiene una cadena de texto JSON que representa un objeto o un arreglo. Muy común en aplicaciones modernas, ya que JSON es ligero, fácil de interpretar en JavaScript y ampliamente soportado.

Ejemplo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Alumnos - XMLHttpRequest con JSON</title>
<style>
table {
	width: 100%;
	border-collapse: collapse;
}
table, th, td {
	border: 1px solid black;
}
th, td {
	padding: 8px;
	text-align: left;
}
th {
	background-color: #f2f2f2;
}
</style>
</head>
<body>
<h1>Lista de Alumnos</h1>
<button id="loadData">Cargar Datos de Alumnos</button>
<table id="studentsTable">
  <thead>
    <tr>
      <th>ID</th>
      <th>Nombre</th>
      <th>Correo Electrónico</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td colspan="3">Cargando datos...</td>
    </tr>
  </tbody>
</table>
<script>
        document.getElementById('loadData').addEventListener('click', function() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'ruta/alumnos.jsom', true);

            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    var students = JSON.parse(xhr.responseText);
                    var tableBody = document.getElementById('studentsTable').getElementsByTagName('tbody')[0];
                    tableBody.innerHTML = ''; 
                    
                    students.forEach(function(student) {
                        var row = document.createElement('tr');

                        var idCell = document.createElement('td');
                        idCell.textContent = student.id;
                        row.appendChild(idCell);

                        var nameCell = document.createElement('td');
                        nameCell.textContent = student.name;
                        row.appendChild(nameCell);

                        var emailCell = document.createElement('td');
                        emailCell.textContent = student.email;
                        row.appendChild(emailCell);

                        tableBody.appendChild(row);
                    });

                    if (students.length === 0) {
                        var noDataRow = document.createElement('tr');
                        var noDataCell = document.createElement('td');
                        noDataCell.textContent = 'No hay alumnos disponibles';
                        noDataCell.colSpan = 3;
                        noDataRow.appendChild(noDataCell);
                        tableBody.appendChild(noDataRow);
                    }
                } else if (xhr.readyState === 4 && xhr.status !== 200) {
                    var tableBody = document.getElementById('studentsTable').getElementsByTagName('tbody')[0];
                    tableBody.innerHTML = '<tr><td colspan="3">Error al cargar los datos</td></tr>';
                }
            };

            xhr.send();
        });
    </script>
</body>
</html>

En este ejemplo, se "parsea" o reconvierte en objeto con el método de javacript JSON.parse y una vez objeto, agrega filas y celdas con datos a la tabla para mostrarlo.

tipo CSV

La respuesta en responseText puede contener datos en formatos menos comunes como CSV (text/csv) . Muy utilizado para datos tabulares o tabulados.

Ejemplo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Alumnos - XMLHttpRequest con CSV</title>
</head>
<body>
<h1>Lista de Alumnos</h1>
<button id="loadData">Cargar Datos de Alumnos</button>
<ol id="alumnos">
  <li>Cargando datos...</li>
</ol>
<script>
        document.getElementById('loadData').addEventListener('click', function() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'ruta/estudiantes.csv', true);

            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    var csv = xhr.responseText;
                    var lines = csv.split('\n'); 
                    var alumnos = document.getElementById('alumnos');
                    alumnos.innerHTML = ''; 

                    lines.forEach(function(line) {
                        if (line.trim() !== '') {
                            var cells = line.split(','); 
                            var listItem = document.createElement('li');
                            listItem.textContent = `ID: ${cells[0]}, Nombre: ${cells[1]}, Correo: ${cells[2]}`;
                            alumnos.appendChild(listItem);
                        }
                    });

                    if (lines.length === 0 || (lines.length === 1 && lines[0].trim() === '')) {
                        var noDataItem = document.createElement('li');
                        noDataItem.textContent = 'No hay alumnos disponibles';
                        alumnos.appendChild(noDataItem);
                    }
                } else if (xhr.readyState === 4 && xhr.status !== 200) {
                    var alumnos = document.getElementById('alumnos');
                    alumnos.innerHTML = '<li>Error al cargar los datos</li>';
                }
            };

            xhr.send();
        });
    </script>
</body>
</html>

En este ejemplo, se toma el valor de responseText y se separa en objetos, primero por salto de línea y después por su caracter separador ",". Con el objeto "parseado" se construye lineas <li> para agregar en la lista ordenada con el id <alumnos>.

Nota:
Como se ve en los ejemplos de los tipos de datos, la programación que vayamos a utilizar para manipular los datos va a depender del tipo de dato que se recibe y qué queremos hacer con él en la página.

Ejercicio:

Crear una Aplicación de Datos de Usuario

  • Crea una página HTML con un botón para cargar los datos de los usuarios y una sección para mostrar los resultados.
  • Utiliza XMLHttpRequest para hacer una solicitud a un archivo y muestra los datos recibidos en la página. Maneja diferentes estados de la solicitud y muestra mensajes de error si la solicitud falla.

Objetivo del capítulo:
Entender y utilizar conversaciones AJAX con jQuery.

jQuery viene con un módulo de conversaciones asincrónicas AJAX desde sus origenes, y tambien tiene "alias" para procesos más rápidos.

.ajax()

Ya vimos que el objetivo de AJAX es cargar contenido en la página web visible sin recargar la página, generando una sensación de "software" o aplicación. jQuery aporta 2 elementos fundamentales en este proceso: Por un lado, reduce la cantidad de programación requerida para la conexión y conversación y por otro lado, resolvía el problema de compatibilidad entre los diferentes navegadores y sus propios métodos XMLHttpRequest de conversación con los que se peleaba antes de estandarización.

La función base o principal es .ajax() y dentro de los paréntesis se pasan los valores para la dirección de conexión, el método a utilizar y qué hacer con la respuesta entre otros posibles valores.

Resumen:
$.ajax({nombre:valor, nombre:valor, ... })

Veamos algunos de los parámetros más comunes que acepta esta función y se le pasa como objeto dentro de los paréntesis.

url

El primer valor lógico es la URL de adonde va a consultar el dato en el servidor, esta puede ser una dirección relativa o absoluta.

Ejemplo:
$.ajax({
    url: "ruta/respuesta.txt"
});

Nota:
Las direcciones en AJAX, por seguridad, suelen ser con respecto al mismo dominio a menos que se afecte el "crossdomain" para hablar con servidores externos.

Cómo vemos en el ejemplo, se está generando una comunicación con el archivo de texto simple respuesta.txt en el servidor.

success

Si queremos utilizar los datos que devuelve el método $.ajax, podemos plantearlo como un callback si es que la conversación fue exitosa o sea en su "success".

Ejemplo:
$.ajax({url: "respuesta.txt", success: function(resultado){
    $("#destino").html(resultado);
  }});

En este ejemplo, cargamos en la variable resultado la respuesta de la conversación y aprovechamos de insertar como html en el objeto con id "destino" en la página.

La otra forma de utilizar la respuesta es con la función .done() de jQuery, o sea cuando ha terminado el proceso de conversación asincrónica con el servidor.

Ejemplo:
$.ajax({
    url: "respuesta.txt",
}).done(function( msg ) {
    alert( "El servidor dice: " + msg );
});

Nota:
jQuery sugiere utilizar la función .done( ) que garantiza esperar la respuesta de datos antes de continuar.

error

De la misma manera, podemos gatillar una respuesta si hay un error de la conversación, ya sea de dirección o de servidor, utilizando el parámetro "error" podemos atrapar"status" o estado y el "statusText" que es el error en texto, muy comodo para mostrar al usuario.

Ejemplo:
$.ajax({url: "respuesta.txt", error: function(xhr){
    alert("Ha ocurrido un error: " + xhr.status + " " + xhr.statusText);
}});

En este ejemplo, atrapamos en la variable xhr con los estados del error para mostrar en un alert() de javascript.

data

Como no todo es traer datos, si no que tambien podemos mandar datos recogidos en la página, se puede definir como uno de los valores el data con un objeto de datos a enviar para ser interpretado por el servidor.

Ejemplo:
$.ajax({
  url: "procesador.php",
  data: { nombre: "Pedro Pablo", apellido: "Pérez Pereira", email:"pobre@pintor.pl" }
}).done(function( msg ) {
    alert(  msg );
  });

En este ejemplo, se envían a "procesador.php" las variables nombre,apellido y email a la página "procesador.php" que tiene la programación para manipular estos datos (ej: mandar correo, registrar en base de dato, consultar registro, etc) y recibir una respuesta terminado el proceso para mostrarlo en un alert() de javascript.

method

Si bien AJAX siempre envía y recibe respuestas, muchas comunicaciones están sujeta al método de la conversación. De manera predeterminada el método nativo GET, pero se puede definir que sea por método POST o método PUT.

Ejemplo:
$.ajax({
  url: "procesador.php",
  method: "POST",
  data: { nombre: "Pedro Pablo", apellido: "Pérez Pereira", email:"pobre@pintor.pl" }
}).done(function(xhr){
    alert(xhr);
});

En este ejemplo, se manda por método "POST" los datos nombre, apellido y email a la página "procesador.php" en el servidor y atrapamos el output de la programación en la variable xhr para mostrarlo en un alert() de javascript.

async

En algunas conversaciones, sobre todo cuando hay un segundo proceso con los datos que se van a recibir del servidor, es que conviene que la conversación no sea asincrónica si no sincrónica, o sea que espera la respuesta para continuar con la conversación. En este caso, podemos afectar el "async" para que sea falso, ya que de manera predeterminada es asincrónica.

Ejemplo:
$.ajax({
  url: "procesador.php",
  method: "POST",
  data: { nombre: "Pedro Pablo", apellido: "Pérez Pereira", email:"pobre@pintor.pl" },
  async: false
}).done(function(xhr){
    alert(xhr);
});

dataType

Ya que el método .ajax( ) puede recibir varios tipos de respuesta de archivo de textos: txt, html, xml, js, JSON, JSONP o script, puede ser que en algunos casos se necesite preprocesar o cambiar la cabecera de la respuesta para facilitar la programación.

Ejemplo:
$.ajax({
  method: "GET",
  url: "mijs.js",
  dataType: "script"
});

En el ejemplo anterior, se carga un archivo javascript que está en el servidor, que és un archivo de texto, pero si queremos gatillar las funciones o rutinas que están definidas en el archivo, podemos decirle que el "dataType" es un "script" para que lo preprocese y lo cargue en la memoria de lo ejecutable.

Demás está recordar que se pueden pasar todas las opciones anteriores en una consulta.

Ejemplo:
$.ajax({
    url: "procesador.php",
    method: "POST",
    data: { nombre: "Pedro Pablo", apellido: "Pérez Pereira", email:"pobre@pintor.pl" },
    async: false,
    dataType: "html"
    error: function(xhr){
        $("#destino").html("Ha ocurrido un error: " + xhr.status + " " + xhr.statusText);
    },
}).done(function(xhr){
    $("#destino").html(xhr);
});

En este caso, enviamos los datos de nuestro usuario como variables y asumimos que en el php del servidor se va a construir un fragmento html como respuesta que vamos a poner en el objeto con el id "destino" en nuestra página. Por ejemplo el mensajea de que el correo se ha enviado exitosamente.

Si bien, la función completa en jQuery es ".ajax( )" , es más común encontrar el uso de sus 3 alias: ".load( )", ".get( )" y ".post( )".

Cualquiera de las 3 funciones puede cargar datos en formato de texto plano: txt, html, xml, js, JSON, JSONP o script, las diferencia están en el método y objetivo que tiene cada una.

.load( )

Esta función permite consultar por el contenido de un archivo externo o un fragmento de él y ponerlo como contenido del objeto seleccionado. Se diferencia de las funciones ".get( )" y ".post( )" en que no envía parámetros extras para procesar la solicitud y de manera predeterminada usa el método GET.

Ejemplo:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Ejemplo de: jQuery - Las 3 preguntas básicas: quién, cuándo, qué.</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body>
<div id="destino"> </div>
<button id="cargar">Cargar contenido</button>
<script>

$(document).ready(function(){
	$("#cargar").click(function(e){
		$("#destino").load("base.txt")
	});
});

</script>
</body>
</html>

load

Otro ejemplo interesante es la capacidad de load de interpretar un HTML y, apesar de traer todo el archivo, puede quedarse con un fragmento hablando con el un id, por ejemplo con el contenido del ID "p2".

Ejemplo:
<body>
<div id="destino"> </div>
<button id="cargar">Cargar contenido</button>
<script>

$(document).ready(function(){
	$("#cargar").click(function(e){
		$("#destino").load("base.html #p2")
	});
});

</script>
</body>
</html>

load2

.get( )

Permite enviar parámetros por el método get, o sea como parte de la dirección URL, al servidor para ser procesados y devolver un resultado.

Ejemplo:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Ejemplo de: jQuery - Las 3 preguntas básicas: quién, cuándo, qué.</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body>
<div id="destino"> </div>
<button id="cargar">Cargar contenido</button>
<script>

$(document).ready(function(){
	$("#cargar").click(function(e){
		$.get("base.php?id=2",function(data,status){
			$("#destino").html(data);
		});
	});
});

</script>
</body>
</html>

get

Otra forma de pasar datos con el método GET es como un objeto en el segundo parámetro

Ejemplo:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Ejemplo de: jQuery - Las 3 preguntas básicas: quién, cuándo, qué.</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body>
<div id="destino"> </div>
<button id="cargar">Cargar contenido</button>
<script>

$(document).ready(function(){
	$("#cargar").click(function(e){
		$.get("base.php",{id:2},function(data,status){
			$("#destino").html(data);
		});
	});
});

</script>
</body>
</html>

.post( )

Esta función permite enviar parámetros por método post al servidor para ser procesado y devolver un resultado.

Ejemplo:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Ejemplo de: jQuery - Las 3 preguntas básicas: quién, cuándo, qué.</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body>
<div id="destino"> </div>
<button id="cargar">Cargar contenido</button>
<script>

$(document).ready(function(){
	$("#cargar").click(function(e){
		$.post("base.php", {'id':2,'color':'red'},function(data, status){
			$("#destino").html(data);
		});
	});
});

</script>
</body>
</html>

post

Ejercicio:

Vitrina virtual

  • Alimentar una página HTML por AJAX con la lista de productos de una tienda online.

Objetivo del capítulo:
Entender y utilizar JSON como formato de dato para comunicaciones asincrónicas.

JavaScript Object Notation (JSON)

JSON no es una función de jQuery, pero, ya que hablamos de AJAX y de ampliar la capacidad de conversación con el servidor con los métodos .post() o .get(), es simpre bueno hablar de este formato de Javascript ahora.

JavaScript Object Notation, o JSON, es la manera que tiene Javascript de convertir en una cadena de texto el contenido de un array u objeto que habitan en la memoria ram del equipo que lo procesa. Es la forma más cómoda que hay para transportar multiples datos, de un servidor, a la página que lo solicita por AJAX para después procesarlo. Veamos un ejemplo.

Ejemplo JSON:

[{ "nombre": "Caperucita", "apellido": "Roja", "email": "caperuza@deferoz.cl", "direccion": "El Bosque 666, Providencia." }, { "nombre": "Pedro Pablo", "apellido": "Pérez Pereira", "email": "pobre@pintor.pl", "direccion": "Pinta paisaje por poca plata,Paris." }, { "nombre": "Dionisio", "apellido": "Tragoalegre", "email": "dionisio@buenvino.cl", "direccion": "Viña San Bebido, Provincia." }, { "nombre": "Klark", "apellido": "Kent", "email": "superman@ligadelajusticia.org", "direccion": "Polo Norte." }]

A simple vista parece un montón de datos sin patrón, pero si lo vemos ordenado, podemos reconocer rápidamente las constantes y anidaciones en la estructura.

Ejemplo:
[{
  "nombre": "Caperucita",
  "apellido": "Roja",
  "email": "caperuza@deferoz.cl",
  "direccion": "El Bosque 666, Providencia."
}, {
  "nombre": "Pedro Pablo",
  "apellido": "Pérez Pereira",
  "email": "pobre@pintor.pl",
  "direccion": "Pinta paisaje por poca plata,Paris."
}, {
  "nombre": "Dionisio",
  "apellido": "Tragoalegre",
  "email": "dionisio@buenvino.cl",
  "direccion": "Viña San Bebido, Provincia."
}, {
  "nombre": "Klark",
  "apellido": "Kent",
  "email": "superman@ligadelajusticia.org",
  "direccion": "Polo Norte."
}]

En este caso, se trata de un objeto con 4 elementos. Dentro de cada uno de ellos, se repiten los 4 valores claves (Nombre, Apellido, Email y Dirección), y cuatro valores distintos para cada elemento.

Como los datos vienen ordenados, con jQuery lo podemos volver a convertir en objeto para utilizarlo en nuestra programación.

Ejemplo:
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>parseJSON</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
    </head>
    <body>
        <div class="container">
            <h1>Lista de alumnos</h1>
            <table class="table table-hover table-striped">
                <thead>
                    <tr>
                        <th>Nombre</th>
                        <th>Apellido</th>
                        <th>Email</th>
                        <th>Dirección</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
        <script>
$(document).ready(function(){
    $.get("alumnos.json",function(data){
        var lafila;
        $.each(data,function(id,fila){
            lafila='<tr><td>'+fila.nombre+'</td><td>'+fila.apellido+'</td><td>'+fila.email+'</td><td>'+fila.direccion+'</td></tr>';
            $("tbody").append(lafila);
        });
    });
});
        </script>
    </body>
</html>

En el ejemplo anterior, llamamos por método get al archivo "alumnos.json" que tiene la lista de alumnos en formato JSON y cargamos en la variable data la respuesta asincrónica. Como sabemos que viene en formato JSON, lo podemos recorrer su estructura con un bucle, agregan al cuerpo de la tabla <tbody> una fila con los cuatro campos de datos.

Uncaught TypeError: Cannot use 'in' operator to search for 'length' in

Puede suceder, que en nuestra interaccion AJAX con JSON y jQuery, el browser nos devuelva el error anterior. Pasa porque no puede hacer el bucle sobre el objeto. Esto puede ser porque el JSON está mal formado, o el tipo de dato no viene correcto.

En el primer caso, hay que copiar el JSON devuelto y utilizar un verificado de formato en línea, hay muchos. Si no es el formato, es el tipo de dato, veamos el siguiente ejemplo.

Ejemplo:
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>parseJSON</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
    </head>
    <body>
        <div class="container">
            <h1>Lista de alumnos</h1>
            <table class="table table-hover table-striped">
                <thead>
                    <tr>
                        <th>Nombre</th>
                        <th>Apellido</th>
                        <th>Email</th>
                        <th>Dirección</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
        <script>
$(document).ready(function(){
    $.get("alumnos.txt",function(data){
        var lafila;
        $.each(data,function(id,fila){
            lafila='<tr><td>'+fila.nombre+'</td><td>'+fila.apellido+'</td><td>'+fila.email+'</td><td>'+fila.direccion+'</td></tr>';
            $("tbody").append(lafila);
        });
    });
});
        </script>
    </body>
</html>

Mismo caso que el ejemplo anterior, salvo que en vez de llamar a un archivo .json, llama al mismo conenido, pero en un archivo .txt. Al no entender el formato, el bucle falla. Para solucionarlo hay dos opciones, jQuery tiene la función getJSON(), similar al método get(), pero especializada para preprosesar el resultado y devolver un JSON ya parseado.

Ejemplo:
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>getJSON</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
    </head>
    <body>
        <div class="container">
            <h1>Lista de alumnos</h1>
            <table class="table table-hover table-striped">
                <thead>
                    <tr>
                        <th>Nombre</th>
                        <th>Apellido</th>
                        <th>Email</th>
                        <th>Dirección</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
        <script>
$(document).ready(function(){
    $.getJSON("alumnos.txt",function(data){
        var lafila;
        $.each(data,function(id,fila){
            lafila='<tr><td>'+fila.nombre+'</td><td>'+fila.apellido+'</td><td>'+fila.email+'</td><td>'+fila.direccion+'</td></tr>';
            $("tbody").append(lafila);
        });
    });
});
        </script>
    </body>
</html>

La otra opción es parsear la cadena con el método parseJSON() de jQuery.

Ejemplo:
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>parseJSON</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
    </head>
    <body>
        <div class="container">
            <h1>Lista de alumnos</h1>
            <table class="table table-hover table-striped">
                <thead>
                    <tr>
                        <th>Nombre</th>
                        <th>Apellido</th>
                        <th>Email</th>
                        <th>Dirección</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
        <script>
$(document).ready(function(){
    $.get("alumnos.txt",function(data){
        var lafila;
        data=$.parseJSON(data);
        $.each(data,function(id,fila){
            lafila='<tr><td>'+fila.nombre+'</td><td>'+fila.apellido+'</td><td>'+fila.email+'</td><td>'+fila.direccion+'</td></tr>';
            $("tbody").append(lafila);
        });
    });
});
        </script>
    </body>
</html>

JSON con PHP

Como JSON es un formato tan importante para transportar multiples contenedores y valores de un lado para otro, PHP tiene 2 funciones: json_encode() que convierte un Array de php en una cadena estructura JSON, y json_decode() que permite convertir en Array de PHP un JSON.

Ejemplo:

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>json_encode</title>
          <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    </head>
    <body>
    <?php 
        $var = array("uno", $dos=2, 'tres', "3+1", $dos+3, number_format(6,2));
        echo "<pre>",print_r(  $var,1),"</pre>";
        echo $eljson=json_encode($var);
        ?>
  </body>
</html>
["uno",2,"tres","3+1",5,"6.00"]

Como resultado, vemos que PHP convierte en una cadena estructurada con los valores del array. Como los contenedores lo está asignando el sistema por su orden de llegada, el JSON resultante no necesita identificar el contenedor en el objeto. Veamos otro ejempo:

Ejemplo:
<?php
      include("conexion.php");
      $query = "SELECT * FROM productos WHERE 1  ORDER BY fecha DESC";
      $resource = $conn->query( $query );
        if($total = $resource->num_rows){
            while ($row = $resource->fetch_assoc()){
                $todas[]=$row;
            }
        echo json_encode($todas);
        }
    ?>

En el ejemplo anterior, estamos consultando a una tabla MySql por la lista completa de los productos con todas sus columnas. Mientras se recorre el resultado $resource extrayendo fila a fila los resultados, se agrega como un nuevo elemento del Array $todas. Al hacer una salida a panatalla del json_encode() de este array no muesetra un JSON parecido a:

[{"id":"7","codigo":"PDDI0000IDDP","nombre":"Rayitas Oblicuas Oli","frase_promocional":"\"Lo\" d\u00edscolo en Rayitas","precio":"3000","fecha":"2016-05-17 11:45:52","categoria":"oblicuas"},{"id":"8","codigo":"KGBAY00YABGK","nombre":"Rayitas Verticales Akastoy","frase_promocional":"Contenci\u00f3n al mejor precio","precio":"2500","fecha":"2016-05-17 11:45:52","categoria":"verticales"},{"id":"9","codigo":"AHH000000HHA","nombre":"Rayitas Horizontales ZZzzz","frase_promocional":"Su sue\u00f1o hecho realidad","precio":"5480","fecha":"2016-05-17 11:45:52","categoria":"horizontales"},{"id":"10","codigo":"VRL000000LRV","nombre":"Rayitas Oblicuas Yupi","frase_promocional":"Vaya de arriba para abajo sin complicaciones","precio":"3640","fecha":"2016-05-17 11:45:52","categoria":"oblicuas"},{"id":"11","codigo":"UHF000000FHU","nombre":"Rayitas Diagonales PAY","frase_promocional":"Direccionales y Multifuncionales","precio":"1000","fecha":"2016-05-17 11:45:52","categoria":"diagonales"},{"id":"12","codigo":"PLOP0000POLP","nombre":"Rayitas Punteadas AKsiAKno","frase_promocional":"La maravillosa posibilidad de elegir","precio":"1245","fecha":"2016-05-17 11:45:52","categoria":"punteadas"},{"id":"13","codigo":"JLQD0000DQLJ","nombre":"Rayitas Verticales Nostah","frase_promocional":"Ci\u00e9rrele la puerta a los abatares","precio":"4750","fecha":"2016-05-17 11:45:52","categoria":"verticales"},{"id":"14","codigo":"OLP000000LPO","nombre":"Rayitas Curvas Pegalawelta","frase_promocional":"Haga un alto en el camino","precio":"4251","fecha":"2016-05-17 11:45:52","categoria":"curvas"},{"id":"15","codigo":"LFLF0000FLFL","nombre":"Rayitas Oblicuas PHP","frase_promocional":"Descubre el programador que hay en ti","precio":"2354","fecha":"2016-05-17 11:45:52","categoria":"oblicuas"},{"id":"17","codigo":"DWE21234DES","nombre":"Rayitas Diagonales CHUEK","frase_promocional":"Un monumeto inquietante","precio":"3500","fecha":"2016-05-17 11:45:52","categoria":"diagonales"},{"id":"6","codigo":"FLMN0000NMLF","nombre":"Rayitas Punteadas Pare-Siga","frase_promocional":"Ideal para sus procesos productivos","precio":"6000","fecha":"2016-05-17 11:40:59","categoria":"punteadas"},{"id":"5","codigo":"MLDI0000IDLM","nombre":"Rayitas Curvas OH-QiDA2","frase_promocional":"El riesgo y la emoci\u00f3n en Rayitas","precio":"1750","fecha":"2016-05-17 11:40:24","categoria":"curvas"},{"id":"4","codigo":"MPD100000DPM","nombre":"Rayitas Diagonales Woderflin","frase_promocional":"Ambiente sus espacios","precio":"2000","fecha":"2016-05-17 11:40:01","categoria":"diagonales"},{"id":"3","codigo":"RPQ300003QPR","nombre":"Rayita Horizontales Ommm","frase_promocional":"El descanso hecho Rayita","precio":"1500","fecha":"2016-05-17 11:39:53","categoria":"horizontales"},{"id":"2","codigo":"579000000975","nombre":"Rayitas Superflex","frase_promocional":"Rayitas Curvas Super Flexibles","precio":"5000","fecha":"2016-05-17 11:39:38","categoria":"curvas"},{"id":"1","codigo":"LFR100001RFL","nombre":"Rayita Vertical","frase_promocional":"La mejor rayita para las paredes vac\u00edas","precio":"1254","fecha":"2016-05-17 11:38:58","categoria":"verticales"},{"id":"16","codigo":"INBOX00XOBNI","nombre":"Rayitas Horizontales OK","frase_promocional":"Haga suyas la leyes de Causa e Efecto","precio":"6540","fecha":"2008-06-05 22:00:56","categoria":"horizontales"}]

En este caso, el objeto JSON devuelto, tiene contenedor y contenido y ahora puede ser devuelto a un AJAX que haya solicitado la lista completa de productos y sus valores.

Ejemplo:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>lista de productos</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>

<body>
<button id="cargar">Cargar datos producto</button>
<table>
  <thead>
  <tr>
    <th>Nombre</th>
    <th>Categoria</th>
    <th>Precio</th>
  </tr>
  </thead>
  <tbody>
  </tbody>
</table>
<script>
$(document).ready(function () {
  $("#cargar").on("click", function () {
    $.post("lista_producto.php", function (data) {
      data = $.parseJSON(data);
      var lafila;
      $.each(data, function (id, fila) {
        lafila = "<tr><td>" + fila.nombre + "</td><td>" + fila.categoria + "</td><td>" + fila.precio + "</td></tr>"
        $("tbody").append(lafila);
      });
    })
  });
});   
</script>
</body>
</html>

En este caso, tenemos un JS que consulta por AJAX al archivo lista_producto.php que tiene la consulta a MySql y devuelve un JSON. El JSON lo toma data y se parsea como JSON con $.parseJSON(data). Como ya es un Array de JS, se puede recorrer con $.each y agrregar a <tbody> la fila <tr> con los valores de cada uno de los elementos del Array.

Ejercicio:
  • Alimentar una página HTML alternativa al home de rayitas, con el mismo diseño, con los productos en la BD MySql de rayitas vía JSON.

Objetivo del capítulo:
Entender y utilizar la APIREST de Wordpress para la conversación vía JSON.

WordPress incorpora una API (Application Programming Interface) REST (REpresentational State Transfer) que devuelve los contenidos de su estructura, según solicitud, en formato JSON (Javascript Object Notation) con el cual podemos extender las capacidades interactivas y dinámicas de los sitios que construimos con WordPress.

El componente base está en la ruta wp-json de nuestra instalación. Y la respuesta en JSON nos muestra a qué cosas puede acceder.

http://www.midominio.cl/wp-json/

Esta URL nos devolverá información general del sitio y los parámetros que podemos agregar a la dirección para especificar la consulta.

Si a wp-json le complementamos con variables GET en la URL, podemos acceder al contenido categorizado de WordPress.

Rutas base para acceder contenido estructurado JSON
Recurso Ruta Base
Posts /wp/v2/posts
Post /wp/v2/posts/<id>
Post Revisions /wp/v2/posts/<id>/revisions
Categories /wp/v2/categories
Tags /wp/v2/tags
Pages /wp/v2/pages
Page /wp/v2/pages/<id>
Page Revisions /wp/v2/pages/<id>/revisions
Comments /wp/v2/comments
Taxonomies /wp/v2/taxonomies
Media /wp/v2/media
Users /wp/v2/users
Post Types /wp/v2/types
Post Statuses /wp/v2/statuses
Settings /wp/v2/settings
Themes /wp/v2/themes
Search /wp/v2/search
Block Types /wp/v2/block-types
Blocks /wp/v2/blocks
Block Revisions /wp/v2/blocks/<id>/autosaves/
Block Renderer /wp/v2/block-renderer
Block Directory Items /wp/v2/block-directory/search
Plugins /wp/v2/plugins

Veamos algunos ejemplos de su uso.

/wp-json/wp/v2/

Esta URL nos devuelve un JSON con todas las direcciones que podemos utilizar para interactuar con el API REST.

wp-json/wp/v2/posts

Esta URL nos devuelve las entradas públicadas de nuestro sitio.

Nota:
De manera predeterminada,el API REST de WordPress muestra sólo 10 resultados, si queremos mostrar más, le podemos pasar parámetros a la URL, por ejemplo: ?per_page=100, que aumentará a 100 los registros a mostrar.

/wp-json/wp/v2/posts/1784

Esta URL nos devuelve un JSON con todo lo que se sabe de la entrada con el id 1784.

A la URL se le pueden pasar parámetros para alterar la query, por ejemplo:

/wp-json/wp/v2/posts?categories=197

Esta URL devuelve todas las entradas de la categoría 197.

/wp-json/wp/v2/posts?_embed&categories=197

Si queremos ver el thumnail o imagen destacada de una entrada como resultado en el JSON del API REST, tenemos que agregar al query _embed como en el ejemplo.

/wp-json/wp/v2/posts?search=texto

Tambien se puede pasar el parámetro search en la URL para que los resultados se filtren dónde exista la palabra "texto".

/wp-json/wp/v2/search?search=interesante

Si queremos ver resultados en páginas, entradas o medios que contengan la palabra "interesante", entonces la URL la apuntamos a search.

/wp-json/wp/v2/pages

Devuelve una JSON con la lista de páginas en el sitio.

Nota:
Más información en la página oficial de la API https://developer.wordpress.org/rest-api/

Alerta:
Si vamos a ocupar el API REST para interactuar con el contenido de nuestro WordPress vía AJAX, hay que recordar usar el método GET o devolverá un error 401.

Ejemplo:
$.get('/wp-json/wp/v2/search?search=interesante').done(function(data, status){
    console.log(data)/*muestra en la consola el objeto con los resultados de la consulta.*/
});
Ejercicio:

Presentación de entradas

  • Genera una plantilla en WordPress que muestre el contenido de las ultimas entradas por AJAX