ajax

Una petición Ajax no es mas que una solicitud a un servidor mediante el objeto XMLHttpRequest de la API Web de los navegadores. La respuesta del servidor es también recibida en el cliente desde javascript y por tanto no implica el cambio de página que ocurría en el envío de información a través de un formulario. Las peticiones Ajax normalmente se usan para solicitar datos al servidor que son manipulados mediante javascript en el cliente y mostrados en la página. El formato preferido de devolución de datos en peticiones Ajax es por tanto JSON. Se puede hacer una petición síncrona, con lo que la ejecución se bloquea hasta que llega la respuesta, o se puede hacer una petición asíncrona, que es lo más habitual, desencadenándose un evento onreadystatechange, del objeto XMLHttpRequest , cuando esté de vuelta la información. La gestión de las peticiones Ajax con el objeto XMLHttpRequest es bastante repetitiva y no siempre sencilla, por lo que se hace normalmente a través de alguna librería como por ejemplo jQuery que facilita enormemente su uso. Todas estas librerías cuando hacen una petición indican en las cabeceras de la solicitud el atributo X-Requested-With con el valor XMLHttpRequest.

En node.js el objeto request de las solicitudes contiene la propiedad xhr que está a true si la solicitud incluye esa cabecera, siendo por tanto la manera de saber si se está haciendo una petición Ajax o una petición de página completa.

Los actuales navegadores incluyen ya, en la API Web, el método fetch que permite hacer peticiones Ajax de una forma más sencilla devolviéndonos un Promise para gestionar las peticiones asíncronas, en forma parecida a como lo hace jQuery. El problema viene de que fetch no incorpora en las cabeceras de la solicitud el atributo X-Requested-With con el valor XMLHttpRequest con lo que la petición en node.js no podrá distinguir si la petición es Ajax o de página completa. Lo que debemos hacer será modificar las cabeceras de la solicitud para incluir el atributo o el tipo de contenido solicitado a json.

En el siguiente ejemplo se ve como hacer una petición POST con los datos de un formulario y devolución de una página completa o una petición Ajax haciendo uso del método fetch con las cabeceras modificadas para que el servidor pueda distinguir peticiones Ajax de las que no.

index.js

const express = require("express");
const hb = require("express-handlebars");
const datos = require("./datos.js");

const app = express();

// para poder recoger los datos enviados con post
app.use(express.urlencoded({ extended: true }));

// recursos estáticos
app.use(express.static("public"));

// activar handlebars
app.set("view engine", "handlebars");
app.engine("handlebars", hb({
    defaultLayout: "main",
}));

app.get("/", (req, res) => {
    res.render("index");
});

app.post("/", (req, res) => {
    if (req.xhr) {
        res.json(datos.empleados[req.body.numero]);
    } else {
        res.render("ficha", { empleado: datos.empleados[req.body.numero] });
    }
});


//si llega aquí, es una página no encontrada
app.use(function(req, res, next) {
    res.type("text/plain");
    res.status(404);
    res.send("no econtrado");
});

app.listen(8080, () => {
    console.log('servidor funcionando en puerto 8080');
});                
            

datos.js

exports.empleados = [{
    nombre: "Pedro",
    apellidos: "García Pérez",
    email: "pgarpe@huerta.es"
},
{
    nombre: "Ángel",
    apellidos: "Menedez Martín",
    email: "anmenma@huerta.es"
},
{
    nombre: "Manuel",
    apellidos: "Santos García",
    email: "mansanga@huerta.es"
}
];                
            

main.handlebars

 
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Huerta S.A.</title>
</head>
<body>
    <h1>Huerta S.A.</h1>
    
</body>
</html>               
           

index.handlebars

<form method="post">
    <p>
        <label for="txtNumeroEmpleado">nº de empleado</label>
        <input type="number" name="numero" id="txtNumeroEmpleado" 
            max="2" min="0" value="0"><br>
        <input type="submit" value="consultar"><br>
    </p>
</form>
<p>
    <label for="txtNumeroEmpleadoAjax">nº de empleado</label>
    <input type="number" name="numero" id="txtNumeroEmpleadoAjax" 
            max="2" min="0" value="0"><br>
    <input type="button" value="consultar Ajax" id="btnConsultar"><br>    
</p>
<p>
    <h2>ficha de empleado</h2>
    <div>nombre: <span id="spnNombre"></span></div>
    <div>apellidos: <span id="spnApellidos"></span></div>
    <div>e-mail: <span id="spnEMail"></span></div>
</p>

<script src="js/index.js"></script>                
            

js/index.js

// petición ajax
document.getElementById("btnConsultar").onclick = (evento) => {
    fetch('/', {
            method: "POST",
            headers: { "Content-Type": "application/x-www-form-urlencoded", 
                        "X-Requested-With": 'XMLHttpRequest' },
            body: "numero=" + document.getElementById("txtNumeroEmpleadoAjax").value
        })
        .then(response => response.json())
        .then(datos => {
            document.getElementById("spnNombre").innerHTML = datos.nombre;
            document.getElementById("spnApellidos").innerHTML = datos.apellidos;
            document.getElementById("spnEMail").innerHTML = datos.email;
        });
}                
            
e-mail:manjarrés