Node.js

Preprocesar variables de templates en express framework (nodejs)

Bien, el caso de uso es el siguiente: tenemos varios templates en los que queremos mostrar mensajes al usuario si los hubiera.
Lo normal seria hacer algo así a la hora de renderizar un template:

Para la página principal:

app.get('index', function (req, res) {
    var messages = req.flash();
    var render_options = {
        titulo: "Página principal"
    };
    if (messages.error || messages.info || messages.success) {
        if (messages.error) messages.hasError = messages.error.length > 0;
        if (messages.info) messages.hasInfo = messages.info.length > 0;
        if (messages.success) messages.hasSuccess = messages.success.length > 0;
        render_options.messages = messages;
    }
    res.render('index', render_options);
});

Para la página del usuario:

app.get('user', function (req, res) {
    var messages = req.flash();
    var render_options = {
        titulo: "Perfil de " + req.session.user.name
    };
    if (messages.error || messages.info || messages.success) {
        if (messages.error) messages.hasError = messages.error.length > 0;
        if (messages.info) messages.hasInfo = messages.info.length > 0;
        if (messages.success) messages.hasSuccess = messages.success.length > 0;
        render_options.messages = messages;
    }
    res.render('index', render_options);
});

Bien, la idea se aprecia, constantemente tenemos que trabajarnos la variable “messages” y si hay mensajes la incluimos en las opciones de renderizado del template.

¿El inconveniente? el código se repite, lo que lo hace poco mantenible y ensucia. Solo por dar un ejemplo, podés ver que estamos preparando errores del tipo “error“, “info” y “success“, y si quisieras agregar un nuevo tipo de error llamado “warning“, te las verías p… negras. Bueno se entiende el inconveniente.

Solución: Encapsular en un preprocesador

Express nos da la posibilidad de preparar variables que van a parar al template haciendo uso de app.use() y res.locals.

NOTA importante: da igual el sistema de templates que uses: Jade, Hogan.js, Mustache, Handlebars, etc. Express es agnóstico en este sentido a la hora de preparar variables. Un puntazo.

Bueno, como decía, podemos agregar un app.use() en app.configure(function () {}); (suele estar en app.js, la base de tu aplicación).
Acá está el ejemplo. Hemos quitado la lógica de tratamiento de mensajes y la hemos colocado en este middleware (si, es uno de esos famosos):

app.use(function (req, res, next) {
    var messages = req.flash();
    if (messages.error || messages.info || messages.success) {
        if (messages.error) messages.hasError = messages.error.length > 0;
        if (messages.info) messages.hasInfo = messages.info.length > 0;
        if (messages.success) messages.hasSuccess = messages.success.length > 0;
        res.locals.messages = messages;
    }
    next();
});

Lo mas notable del código anterior es que hemos asignado el resultado a res.locals.messages. res.locals, va a “mergearse” con las variables que uses en res.render() antes de llamar al template.
NOTA: next(); es necesario para que el flow de ejecución siga adelante.

Hecho lo anterior, les presento las versiones simplificadas de los ejemplos que di al principio:

app.get('index', function (req, res) {
    var render_options = {
        titulo: "Página principal"
    };
    res.render('index', render_options);
});
app.get('user', function (req, res) {
    var render_options = {
        titulo: "Perfil de " + req.session.user.name
    };
    res.render('index', render_options);
});

Mucho mejor ¿no?

Chau!

Comentarios

  1. Wilfredo E. Miles

    Lo mas notable del código anterior es que hemos asignado el resultado a res.locals.messages. res.locals, va a “mergearse” con las variables que uses en res.render() antes de llamar al template. NOTA: next(); es necesario para que el flow de ejecución siga adelante.

    Responder

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>