I have dynamic html page what using Node.js and SWIG template engine. I need call function from my SWIG template to get user data from database to render page content. SWIG call function but not wait for response from database. So, is it possible to call async function and return data to swig template?
My SWIG template: todos.html
<body>
{%set todos=getTodos()%}
{%for item in todos%}
<div>{{item.name}}</div>
<div>{{item.completed}}</div>
{%endfor%}
</body>
My node server (using express):
.......
swig.setDefaults({locals:{getTodos:function(input){
setTimeout(function(){
return [
{name:"First todo",completed:false},
{name:"Same name",completed:true},
]
},5000)
})
........
But page was rendered without waiting for data that come from "timeout".
So basically no, you cannot use the async functions directly in the template. It's not supported.
But you can still do what you want by simply getting all the data you need asynchronously first and then rendering the swig template.
Here is the minimal example:
const swig = require('swig');
const express = require('express');
const app = express();
const swigEngine = new swig.Swig();
app.engine('html', swigEngine.renderFile);
app.set('view engine', 'html');
const loadTodos = function (callback) {
setTimeout(function () {
const todos = [
{name: "First todo", completed: false},
{name: "Same name", completed: true},
];
callback(null, todos);
}, 1000)
};
app.get('/', (req, res) => {
// So first you get the data asynchronously
loadTodos(function (err, data) {
if (err) {
res.sendStatus(400);
return;
}
res.render('index', {todos: data});
})
});
app.listen(5555, () => console.log('Server is running on port 5555.'))
Also you template gets more simple if you do it like that:
{%for item in todos%}
<!-- You have missed the curly brackets here {{}} -->
<div>{{item.name}}</div>
<div>{{item.completed}}</div>
{%endfor%}