What is the proper way to check for existence of variable in an EJS template (using ExpressJS)?
Asked Answered
E

21

161

On the EJS github page, there is one and only one simple example: https://github.com/visionmedia/ejs

Example

<% if (user) { %>
    <h2><%= user.name %></h2>
<% } %>

This seems to be checking for the existence of a variable named user, and if it exists, do some stuff. Duh, right?

My question is, why in the world would Node throw a ReferenceError if the user variable doesn't exist? This renders the above example useless. What's the appropriate way to check for the existence of a variable? Am I expected to use a try/catch mechanism and grab that ReferenceError?

ReferenceError: user is not defined
    at IncomingMessage.anonymous (eval at <anonymous> (/usr/local/lib/node/.npm/ejs/0.3.1/package/lib/ejs.js:140:12))
    at IncomingMessage.<anonymous> (/usr/local/lib/node/.npm/ejs/0.3.1/package/lib/ejs.js:142:15)
    at Object.render (/usr/local/lib/node/.npm/ejs/0.3.1/package/lib/ejs.js:177:13)
    at ServerResponse.render (/usr/local/lib/node/.npm/express/1.0.7/package/lib/express/view.js:334:22)
    at Object.<anonymous> (/Users/me/Dropbox/Projects/myproject/server.js:188:9)
    at param (/usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:146:21)
    at pass (/usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:162:10)
    at /usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:152:27
    at Object.restrict (/Users/me/Dropbox/Projects/myproject/server.js:94:5)
    at param (/usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:146:21)

I understand that I could make this error go away by simply adding a "user" local variable in my server code, but the whole point here is that I want to check for the existence of such variables at runtime using your every day if/else nullcheck type pattern. An exception for a variable that doesn't exist seems ridiculous to me.

Estis answered 21/3, 2011 at 0:9 Comment(0)
A
200

The same way you would do it with anything in js, typeof foo == 'undefined', or since "locals" is the name of the object containing them, you can do if (locals.foo). It's just raw js :p

Apograph answered 21/3, 2011 at 0:22 Comment(9)
I'm beginning to wonder if I've got a bigger problem on my hands. This throws a Reference Error too: <% alert('test'); %>Estis
@Aashay alert is part of a browser's window object, and not available in node.js. The alternative is console.log, though I don't know if it's available in an ejs template unless you pass it in via locals.Bragi
@Bragi In this case I'm looking specifically for EJS, so it's on the browser page. But, like TJ said, typeof foo == 'undefined' works. I learned that I could also add a simple !!foo if foo has been defined but is null or empty.Estis
Is there a shorthand for this? Why doesn't EJS simply honor the if (foo) case?Tolentino
is locals.foo the same as foo?Kondon
I have the same problem. I have to check if(locals.foo) instead of just checking if(foo).Od
if (locals.user){ } FTWCromorne
<% if (locals.foo) { %> Here is the variable: <%= foo %> <% } %>Biondo
This is wrong. In ejs, if you do a type check or any check on an undefined variable, it throws an error. Every time. The above answer typeof foo == 'undefined' is incorrect.Asymptomatic
C
49

Try prepending the variable with locals

Example: if(locals.user){}

Catsup answered 24/3, 2017 at 7:43 Comment(0)
B
33
<% if (locals.user) { %>

 // Your logic goes here 

<% } %>
Bartram answered 11/9, 2017 at 14:8 Comment(0)
A
15

You can create a view helper which checks for "obj === void 0", this one is for express.js:

res.locals.get = function() {
    var args = Array.prototype.slice.call(arguments, 0);
    var path = args[0].split('.');
    var root = this;
    for (var i = 0; i < path.length; i++) {
        if(root[path[i]] === void 0) {
            return args[1]?args[1]:null;
        } else {
            root = root[path[i]];
        }
    };
    return root;
}

Then use it in the view like

<%- get('deep.nested.non.existent.value') %>  //returns: null
<%- get('deep.nested.non.existent.value', "default value") %> //returns: default value
Antimasque answered 21/1, 2014 at 14:33 Comment(5)
not sure why this was downvoted, its rather elegant in my opinion.Neon
What is the difference between <%= and <%-?Steerage
@Steerage As per the documentation, under "Tags": <%= HTML escapes the value first; <%- outputs the unescaped value. So <b> would become a bold tag when using <%-, but simply the text "<b>" when using <%=Piety
Thank you! I had no idea <%- was even a valid tag.Steerage
I know it's a long dated post, but how can I implement this ? I tried on my own, but can't find how to properly convert this to a helper. thank you.Grube
C
13

To check if user is defined, you need to do that:

<% if (this.user) { %>
   here, user is defined
<% } %>
Cytoplasm answered 19/2, 2014 at 14:22 Comment(2)
This does not work in the most up-to-date EJS library (1.0.0). Although valid Javascript, EJS will refuse to act as expected.Dessiatine
Does not work for me. Even though I have defined foo, else clause is still evaluated. Tested with EJS 2.3.4 EDIT: using locals in place of this worksUlloa
P
9

I've come across the same issue using node.js with mongoose/express/ejs when making a relation between 2 collections together with mongoose's populate(), in this case admins.user_id existed but was related to an inexistant users._id.
So, couldn't find why:

if ( typeof users.user_id.name == 'undefined' ) ...

was failing with "Cannot read property 'name' of null" Then I noticed that I needed to do the checking like this:

if ( typeof users.user_id == 'undefined' ) ...

I needed to check the "container" of 'name', so it worked!
After that, this worked the same:

if ( !users.user_id ) ...  

Hope it helps.

Purpleness answered 17/10, 2013 at 21:50 Comment(1)
Anyway, can't believe there so few official documentation on EJS... they don't update their documentation since 2010!!!Purpleness
S
4

This may help somebody.

<p><%= locals?.message %></p>

or

<p><%= locals.message || '' %></p>
Sulphanilamide answered 8/4, 2021 at 1:1 Comment(0)
C
3

Came to this page for an answer but I came up with a shorter inline syntax for it which is:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>
Choosy answered 31/5, 2018 at 23:32 Comment(1)
This is dangerous to use, because if the object 'user' does not have a 'name' property, the ejs rendering will fail.Helenhelena
D
2

What I do is just pass a default object I call 'data' = '' and pass it to all my ejs templates. If you need to pass real data to ejs template, add them as property of the 'data' object.

This way, 'data' object is always defined and you never get undefined error message, even if property of 'data' exist in your ejs template but not in your node express route.

Denys answered 13/7, 2016 at 13:18 Comment(0)
E
2

For your if statement you need to use typeof:

<% if (typeof user == 'object' && user) { %>

<% } %>
Ephemeral answered 19/7, 2016 at 8:16 Comment(0)
E
2

Update 2022

Use the locals object

This will print the variable if it exists

<%= locals?.yourvariable %>

You can also do

This will run a condition if the variable exists

<% if(locals.yourvariable) { %>
<% } %>
Estelleesten answered 2/8, 2022 at 12:51 Comment(0)
R
1

The safest and only solution that worked for me

<% if (typeof user !== 'undefined' && typeof user.name !== 'undefined') { %>
    <h2><%= user.name %></h2>
<% } %>

Or a short version

<% (typeof user !== 'undefined' && typeof user.name !== 'undefined') ? user.name : '' %>
Rebecarebecca answered 14/2, 2022 at 10:56 Comment(0)
G
1

Here is the solution you've been looking for:

I just fixed it now.

Code:

<% if(typeof(username)==='undefined') username='Login' %>

Output:

If username exists, then it will be shown as it is. Otherwise username will contain the string 'Login'.

Grader answered 7/3, 2023 at 10:52 Comment(0)
H
0

I had same issue, and luckily, I found that there is also a short-circuit function in JS (I knew there was one in Ruby and some other languages).

On my server/controller side (this is from Node.js/Express):

return res.render('result', {survey_result : req.session.survey_result&&req.session.survey_result.survey }); 

See what I did there? The && which follows after a possibly undefined variable (i.e. request.session.survey_result object, which might or might not have form data) is the short-circuit notation in JS. What it does is only evaluate the part that follows the && if the part to the left of the && is NOT undefined. It also does not throw an error when the left part IS undefined. It just ignores it.

Now, in my template (remember that I passed the object req.session.survey_result_survey object to my view as survey_result ) and then I rendered fields as:

<table>
    <tr>
        <td> Name:</td>
        <td> <%=survey_result&&survey_result.name%></td>
    </tr>
    <tr>
        <td> Dojo Location:</td>
        <td> <%=survey_result&&survey_result.dojo_loc%></td>
    </tr>
    <tr>
        <td> Favourite Language:</td>
        <td> <%=survey_result&&survey_result.fave_lang%></td>
    </tr>

I used short-circuit there also, just for safe-keeps.

When I tried it with previously suggested ways, just:

<% if (typeof survey_result !== undefined) { %>
... <!-- some js and/or html code here -->
<% } %>

Sometimes, it would still try to evaluate the properties within the IF statement...Maybe someone can offer an explanation as to why?

Also, I wanted to correct that undefined needs to be without the single quotes, as I saw done in previous examples. Because the condition will never evaluate to true, as you are comparing a String value 'undefined' with a datatype undefined.

Hertzog answered 15/1, 2018 at 22:53 Comment(0)
T
0

You can use this trick :

user.name // stops code execution,if user is undefined
(scope.user||0).name // === undefined

where scope is parent object of user

Tobias answered 22/12, 2019 at 18:30 Comment(0)
A
0

if you plan to use the same object often, you could use a function like this:

<% function userObj(obj){
    //replace user with what you name your object
    if(typeof user === 'object'){
        let result = user;
        if(obj){
            obj = obj.split('.');
            for(let i = 0; i < obj.length; i++){
                if(obj[i] && obj[i].trim() !== '' && result[obj[i]]){
                    result = result[obj[i]];
                }else{
                    result = false;
                    break;
                }
            }
        }
        return result;
    }
    return false;
} %>

usage:

<% if(userObj('name')){
    <h2><%= userObj('name') %></h2>
} %>
Allergic answered 7/1, 2020 at 19:55 Comment(0)
A
0

I have come up with another solution.

<% if(user){ %>
   <% if(user.name){ %>
     <h1><%= user.name %></h1>
<%}}%>

I hope this helps.

Assumed answered 25/4, 2020 at 18:26 Comment(1)
You can join both conditionals in just one evaluation: if (user && user.name)Breathless
A
0

I read somewhere using locals isn't perfect so I came up with something like this, for example:

in express file:

const toRender = {
 user: false,
};
//...
if (userExists) {
 toRender.user = true;
 toRender.data = userData;
}
res.render("site", {info: toRender});

and in ejs template:

<% if (info.user) { %>
    <h2><%= info.data.name %></h2>
<% } %>
Aba answered 3/8, 2022 at 13:37 Comment(0)
J
0

I wanted to use one template and conditionally display a bit more data.

I tried <? more_data = more_data ?? false ?>, which is how I prefer to do it in typescript (and other languages that support it). This would fix it in PHP, as php is pretty null-tolerable at set-time, but less so at read-time (works great).

After reading some answers here..

<? more_data = locals.more_data ?? false ?>

Jameyjami answered 14/3, 2023 at 10:21 Comment(0)
L
0

UPDATE 2024

I know it has been answered for a long time, but since none of the answers above did the trick, this is what worked for me :

<% if(typeof myVariable !== 'undefined') { %>
    // Variable exists
<% } %>
Lubricate answered 22/12, 2023 at 22:18 Comment(0)
H
-2

I found what I believe to be a better solution on Joe Andrieu's blog:

<%= user.name ? user.name : '' %>

This applies in more situations than the other answers (i.e., when you need to check if a single property exists).

Herakleion answered 6/2, 2021 at 5:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.