express
express copied to clipboard
Added local variables on render
Hi,
I'm using express and ejs. I passed an object to res.render then called a for in loop on it on the template but when it's printed it has _locals inside too. Everywhere i checked inside the object it wasn't there, yet on output to the end user it has this extra variable. I didn't find anything directly on this but a couple of other issues kinda point out that local variables are automatically included in the response to the view and yet i have never encountered this situation before.
I had to do a hacky solution for this with an if statement checking for this and ignoring it.
Any other comments on this?
There is nothing in express that is adding something called _locals
that I am aware of. Can you provide a reproducible example of the issue you are having? Does it happen with all template engines or only ejs?
That was a fast reply and an unexpected answer. Sure i"l try to provide anything i can. No i haven't used or tried anything but EJS.
Here is the code:
groupby(Function)
const groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
Route
app.get('/test', async (req, res) => {
t = await db.getQuestions(1);
zz = groupBy(t, 'question');
res.render('pages/test', zz);
});
View(EJS):
<% for( const property in zz ) { %>
<p><%= property %></p>
<% } %>
As far as the Data, this is how it looks like after each step:
From DB
[
{
question_id: 1,
question: 'Lorem ipsum dolor sit amet',
answer: 'Lorem',
value: 1
},
{
question_id: 1,
question: 'Lorem ipsum dolor sit amet',
answer: 'ipsum',
value: 3
},
{
question_id: 1,
question: 'Lorem ipsum dolor sit amet',
answer: 'dolor',
value: 5
},
]
After groupBy:
{
'Lorem ipsum dolor sit amet': [
{
question_id: 1,
question: 'Lorem ipsum dolor sit amet',
answer: 'Lorem',
value: 1
},
{
question_id: 1,
question: 'Lorem ipsum dolor sit amet',
answer: 'ipsum',
value: 3
},
{
question_id: 1,
question: 'Lorem ipsum dolor sit amet',
answer: 'dolor',
value: 5
}
],
}
In the FE:
<p>Lorem ipsum dolor sit amet</p>
<p>_locals</p>
BTW if i stringify the object on render
res.render('pages/test', JSON.stringify(zz));
I get the following error:
(node:337233) UnhandledPromiseRejectionWarning: TypeError: Cannot create property '_locals' on string
So i'm thinking render adds that property on any object it sends.
Update:
Just tried putting that object in an object when rendering and that made the problem go away
res.render('pages/test', {zz});
Very strange but somehow related to passing an object directly to render rather than inside an object. Never had a problem before...
Here is the link from Express Documentation regarding res.render
. You should pass variables to views as an object. Regarding the _locals
, it is still not obvious to me how to reproduce the bug, seems like you are calling the _locals
yourself in the view.
@mrmammadov What do you mean i'm calling it in the view? where do you see it in my example code? I've only seen it on the end client and not anywhere before that so no idea how it got there
I am sorry, it was a misunderstanding. Although I still cannot reproduce your issue, passing the variable as an object in render
function will give you desired outcome.
I am sorry, it was a misunderstanding. Although I still cannot reproduce your issue, passing the variable as an object in
render
function will give you desired outcome.
No worries, at first i also thought the same however i somehow broke it.
It's been a while but i still have that code somewhere, let me see if i can reproduce it myself and then i"ll make a new repo so you can test it too.
If i fail at reproducing then i"ll come back to close the issue.
Hi,
Sorry it took so long to reply back I was able to recreate this at the end, here is a demo as promised: https://github.com/JStyle21/testing
The _locals
key is added to res.render(view, options)
options here:
https://github.com/expressjs/express/blob/508936853a6e311099c9985d4c11a4b1b8f6af07/lib/response.js#L1001-L1004
You are passing an object literal that is treated as options
, to prevent this from happening you need to specify a key for it as you already suggested here.
The right code is definitely this:
app.get('/', (req, res) => {
const zz = { 1: 1, 2: 2, 3: 3 };
return res.render('reg', { zz });
});
@JStyle21 I'm closing this issue as @fedeci has given you the solution. Feel free to get back if the issue is still present and I'll reopen this issue.