Guía Completa de AJAX: Asynchronous JavaScript and XML

  Conceptos Fundamentales

AJAX (Asynchronous JavaScript and XML) es una técnica de desarrollo web que permite:

  • Actualizar una página web sin recargarla completamente
  • Solicitar y recibir datos del servidor en segundo plano
  • Enviar datos al servidor en segundo plano
  • Actualizar partes específicas de una página web

  Ventajas de usar AJAX

  • Mejor experiencia de usuario
  • Reducción de tráfico del servidor
  • Respuestas más rápidas
  • Actualizaciones parciales de página

Sintaxis Básica Usando XMLHttpRequest

javascript
// Crear una instancia de XMLHttpRequest
let xhr = new XMLHttpRequest();

// Configurar la solicitud
xhr.open('GET', 'url-del-servidor', true);

// Configurar el manejador de eventos
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
      console.log(xhr.responseText);
  }
};

// Enviar la solicitud
xhr.send();
  Explicación

  • XMLHttpRequest permite hacer solicitudes HTTP asíncronas en JavaScript, obteniendo datos del servidor sin recargar la página.
  • Primero, se crea una instancia de XMLHttpRequest y se configura con open(), donde especificamos el método (GET), la URL y si es asíncrona (true).
  • En onreadystatechange, se revisa si la solicitud terminó (readyState === 4) y fue exitosa (status === 200). Finalmente, se envía la solicitud con send(), y el servidor responde con responseText.

Usando AJAX con jQuery

AJAX con jQuery simplifica las solicitudes al servidor. Con $.ajax(), defines la URL, método, tipo de datos y funciones de éxito y error, gestionando la respuesta y errores fácilmente.

javascript
$.ajax({
  url: 'url-del-servidor',
  method: 'GET',
  dataType: 'json',
  success: function(response) {
      console.log(response);
  },
  error: function(xhr, status, error) {
      console.error(error);
  }
});

Métodos Comunes y Ejemplos


GET - Obtener Datos

javascript
// Usando jQuery
$.get('api/usuarios', function(data) {
  console.log(data);
});


// Usando jQuery con $.ajax() y GET
$.ajax({
  url: 'api/usuarios',
  method: 'GET',
  dataType: 'json',
  success: function(data) {
      console.log(data);
  },
  error: function(xhr, status, error) {
      console.error(error);
  }
});


// Usando Fetch API (moderno)
fetch('api/usuarios')
  .then(response => response.json())

POST - Enviar Datos

javascript
// Usando jQuery
$.post('api/usuarios', {
  nombre: 'Juan',
  edad: 25
}, function(response) {
  console.log(response);
});

// Usando jQuery con $.ajax()
$.ajax({
  url: 'api/usuarios',
  method: 'POST',
  data: { nombre: 'Juan', edad: 30 },
  success: function(response) {
      console.log(response);
  },
  error: function(xhr, status, error) {
      console.error(error);
  }
});

// Usando Fetch API
fetch('api/usuarios', {
  method: 'POST',
  headers: {
      'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      nombre: 'Juan',
      edad: 25
  })
})
.then(response => response.json())
.then(data => console.log(data));

PUT - Actualizar Datos

javascript
// Usando jQuery con $.ajax() y PUT

$.ajax({
  url: 'api/usuarios/1',
  method: 'PUT',
  data: {
      nombre: 'Juan Actualizado',
      edad: 26
  },
  success: function(response) {
      console.log(response);
  }
});

DELETE - Eliminar Datos

javascript
// Usando jQuery con $.ajax() y DELETE

$.ajax({
  url: 'api/usuarios/1',  // URL con un ID para eliminar un usuario específico
  method: 'DELETE',
  success: function(response) {
      console.log('Usuario eliminado:', response);
  },
  error: function(xhr, status, error) {
      console.error('Error al eliminar:', error);
  }
});

Cómo Enviar un Formulario HTML a PHP Usando AJAX

html
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Formulario de Registro</title>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
  <h2>Formulario de Registro</h2>
  <form id="formularioRegistro">
      <label for="nombre">Nombre:</label>
      <input type="text" id="nombre" name="nombre" required><br><br>

      <label for="email">Correo Electrónico:</label>
      <input type="email" id="email" name="email" required><br><br>

      <button type="submit">Enviar</button>
  </form>

  <script>
      $('#formularioRegistro').submit(function(e) {
          e.preventDefault();
          
          $.ajax({
              url: 'registro.php',
              method: 'POST',
              data: $(this).serialize(),
              success: function(response) {
                  alert('Registro exitoso: ' + response);
              },
              error: function(xhr) {
                  alert('Error en el registro');
              }
          });
      });
  </script>
</body>
</html>

PHP (registro.php)

php
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  $nombre = $_POST['nombre'];
  $email = $_POST['email'];

  // Simular registro exitoso (aquí puedes guardar en la base de datos si quieres)
  echo "Nombre: $nombre, Email: $email";
} else {
  echo "Solicitud inválida";
}
?>
  Explicación

  • HTML: Crea un formulario básico con campos de nombre y correo. id="formularioRegistro" se usa para capturar la acción de envío.
  • JavaScript/jQuery: Al enviar el formulario, se evita la recarga con e.preventDefault(). Luego, se hace una solicitud AJAX a registro.php enviando los datos serializados.
  • PHP: Recibe y procesa los datos enviados por POST y devuelve un mensaje de confirmación.

Cómo Crear un Contador Interactivo con AJAX y Bootstrap 5

html
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Contador con AJAX</title>
  <link
    href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css"
    rel="stylesheet"
  />
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
  <div class="container my-5 text-center">
    <h2>Contador</h2>
    <div id="contador" class="display-4">0</div>
    <button id="aumentar" class="btn btn-success">Aumentar</button>
    <button id="disminuir" class="btn btn-danger">Disminuir</button>
  </div>

  <script>
    $(document).ready(function () {
      let valorContador = 0;

      // Función para actualizar el contador
      function actualizarContador() {
        $("#contador").text(valorContador);
      }

      // Aumentar contador
      $("#aumentar").click(function () {
        valorContador++;
        $.ajax({
          url: "actualizar_contador.php",
          method: "POST",
          data: { contador: valorContador },
          success: function (response) {
            console.log("Contador aumentado:", response);
            actualizarContador();
          },
          error: function (xhr) {
            console.error("Error al aumentar:", xhr);
          },
        });
      });

      // Disminuir contador
      $("#disminuir").click(function () {
        // Solo disminuir si valorContador es mayor que 0
        if (valorContador > 0) {
          valorContador--;
          $.ajax({
            url: "actualizar_contador.php",
            method: "POST",
            data: { contador: valorContador },
            success: function (response) {
              console.log("Contador disminuido:", response);
              actualizarContador();
            },
            error: function (xhr) {
              console.error("Error al disminuir:", xhr);
            },
          });
        } else {
          alert("El contador no puede ser negativo.");
        }
      });
    });
  </script>
</body>
</html>

PHP (actualizar_contador.php)

php
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  $contador = $_POST['contador'];

  // Aquí puedes guardar el contador en una base de datos si lo deseas
  echo "Contador actualizado a: " . $contador;
} else {
  echo "Solicitud inválida";
}
?>
  Explicación

HTML:

  • Se crea un contador que inicialmente muestra 0 y dos botones, uno para aumentar y otro para disminuir.
  • Se utiliza Bootstrap para un diseño simple y limpio.

JavaScript/jQuery:

  • Se inicializa valorContador en 0.
  • Al hacer clic en los botones de aumentar y disminuir, se incrementa o decrementa el contador respectivamente.
  • Se realiza una solicitud AJAX a actualizar_contador.php para enviar el nuevo valor del contador, y se actualiza la visualización del contador en la página.

PHP:

  • Se recibe el nuevo valor del contador por POST y se puede utilizar para realizar cualquier operación (como guardarlo en una base de datos).
  • Se devuelve un mensaje de confirmación con el nuevo valor del contador.

Validación de Nombre de Usuario en Tiempo Real con jQuery, $.ajax() y PHP

html
<!-- Archivo index.html --->
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Validación de Usuario en Tiempo Real</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet">
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <style>
      #mensaje {
          margin-top: 10px;
      }
  </style>
</head>
<body>

<div class="container my-5">
  <h1 class="text-center">Registro de Usuario</h1>
  <form id="formRegistro" method="POST">
      <div class="mb-3">
          <label for="nombreUsuario" class="form-label">Nombre de Usuario:</label>
          <input type="text" class="form-control" id="nombreUsuario" name="username" required>
      </div>
      <div id="mensaje"></div>
      <button type="submit" class="btn btn-primary">Registrar</button>
  </form>
</div>

<script>
  $('#nombreUsuario').blur(function() {
      let usuario = $(this).val();
      
      $.ajax({
          url: 'api/verificar-usuario.php',
          method: 'GET',
          data: { username: usuario },
          success: function(response) {
              const data = JSON.parse(response);
              if (data.disponible) {
                  $('#mensaje').text('Usuario disponible').css('color', 'green');
              } else {
                  $('#mensaje').text('Usuario ya existe').css('color', 'red');
              }
          },
          error: function(xhr) {
              console.error('Error en la verificación:', xhr);
          }
      });
  });
</script>

</body>
</html>

PHP (verificar-usuario.php)

php
<?php
// Conectar a la base de datos (ajusta según tu configuración)
$host = 'localhost';
$db = 'nombre_base_datos';
$user = 'usuario_db';
$pass = 'clave_bd';

$conn = new mysqli($host, $user, $pass, $db);

// Verificar conexión
if ($conn->connect_error) {
  die("Conexión fallida: " . $conn->connect_error);
}

// Obtener el nombre de usuario desde la solicitud GET
$username = $_GET['username'];

// Consultar si el nombre de usuario existe en la base de datos
$query = "SELECT COUNT(*) FROM usuarios WHERE username = '$username'";
$result = $conn->query($query);
$row = $result->fetch_array();

// Cerrar la conexión
$conn->close();

// Devolver respuesta JSON
$response = array("disponible" => $row[0] == 0);
header('Content-Type: application/json');
echo json_encode($response);
?>
  Nota

El archivo index.html proporciona un formulario para registrar un nombre de usuario. Al dejar el campo, se envía una solicitud AJAX a verificar-usuario.php para comprobar si el nombre está disponible. La respuesta se muestra en la interfaz.

verificar-usuario.php verifica en la base de datos si el nombre de usuario ya existe. Devuelve un JSON que indica si está disponible, permitiendo al frontend actualizar la interfaz sin recargar la página.

Manejo de Errores

Este código realiza una solicitud AJAX para obtener datos de la URL ‘api/datos’ utilizando el método GET. Si la solicitud es exitosa, se registran los datos en la consola; si ocurre un error, se verifica el código de estado para mostrar mensajes específicos de error, como “Recurso no encontrado” (404) o “Error del servidor” (500). Finalmente, la función complete se ejecuta siempre al finalizar la solicitud, ya sea con éxito o error, registrando “Solicitud completada”.

javascript
$.ajax({
  url: 'api/datos',
  method: 'GET',
  success: function(response) {
      console.log(response);
  },
  error: function(xhr, status, error) {
      if (xhr.status === 404) {
          console.error('Recurso no encontrado');
      } else if (xhr.status === 500) {
          console.error('Error del servidor');
      } else {
          console.error('Error: ' + error);
      }
  },
  complete: function() {
      // Se ejecuta siempre, sin importar éxito o error
      console.log('Solicitud completada');
  }
});

Mejores Prácticas

  1. Siempre manejar errores
  2. Mostrar indicadores de carga
javascript
$(document).ajaxStart(function() {
  $('#loadingIndicator').show();
}).ajaxStop(function() {
  $('#loadingIndicator').hide();
});
  jQuery

Este código utiliza jQuery para gestionar un indicador de carga durante las solicitudes AJAX. Cuando se inicia una solicitud AJAX, el elemento con el ID loadingIndicator se muestra, y cuando la solicitud finaliza, ya sea con éxito o con error, el indicador se oculta. Esto mejora la experiencia del usuario al proporcionar una señal visual de que se está procesando una solicitud.

Usar Promise/async-await para código más limpio

javascript
async function obtenerDatos() {
  try {
      const response = await fetch('api/datos');

      // Verifica si la respuesta es exitosa
      if (!response.ok) {
          throw new Error('Error en la solicitud: ' + response.status);
      }

      // Convierte la respuesta en formato JSON
      const data = await response.json();
      return data; // Devuelve los datos obtenidos
  } catch (error) {
      console.error('Error:', error);  // Manejo de errores
  }
}


// Opción 1: Usando await
async function obtenerYMostrarDatos() {
  const dataBD = await obtenerDatos();
  console.log(dataBD); // Ahora dataBD contendrá los datos obtenidos
}

// Llamada a la función
obtenerYMostrarDatos();

// Opción 2: Usando then
obtenerDatos().then(dataBD => {
  console.log(dataBD); // Manejo de datos aquí
});

Usar async-await para código más limpio

ejemplo que usa solo async/await y maneja la obtención de datos sin involucrar promesas explícitas (es decir, sin usar .then()).

javascript
async function obtenerDatos() {
  try {
      const response = await fetch('api/datos'); // Cambia 'api/datos' por tu URL real

      // Verifica si la respuesta es exitosa
      if (!response.ok) {
          throw new Error('Error en la solicitud: ' + response.status);
      }

      const data = await response.json(); // Convierte la respuesta en formato JSON
      console.log('Datos recibidos:', data); // Muestra los datos obtenidos
  } catch (error) {
      console.error('Error:', error); // Manejo de errores
  }
}

// Llamando a la función
obtenerDatos();
  Explicación

  • async function obtenerDatos(): Declara una función asíncrona que permite el uso de await dentro de ella.
  • await fetch('api/datos'): Realiza la solicitud a la API y espera hasta que la respuesta esté disponible. Si la respuesta no es exitosa (código de estado HTTP no OK), se lanza un error.
  • await response.json(): Convierte la respuesta de la API en formato JSON y espera a que esta conversión se complete.
  • Manejo de errores: Se utilizan bloques try/catch para manejar cualquier error que pueda ocurrir durante la solicitud o la conversión de datos.

Este código se ejecuta al llamar a obtenerDatos(), y no utiliza promesas explícitas en su manejo.