使用ExpressJS的EJS模板中检查变量存在的正确方法是什么?

159

在 EJS 的 github 页面上,只有一个简单的示例:

https://github.com/visionmedia/ejs

示例

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

看起来这是在检查名为"user"的变量是否存在,如果存在,则执行一些操作。 显然,对吧?

我的问题是,为什么如果"user"变量不存在,Node会抛出ReferenceError?这使上面的示例无用。有什么适当的方法来检查变量是否存在吗?我需要使用try/catch机制并捕获那个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)
我知道可以通过在服务器代码中添加一个"用户"本地变量来消除这个错误,但这里的重点是我想使用您每天使用的if/else空值检查类型模式在运行时检查这些变量的存在。对于不存在的变量的异常对我来说似乎很荒谬。
20个回答

2
我的工作就是将一个我称之为“数据”的默认对象传递给所有的ejs模板。 如果你需要向ejs模板传递真实的数据,请将其作为“data”对象的属性添加。
这样,“data”对象始终被定义,并且即使在你的ejs模板中存在但不在你的node express路由中,也永远不会产生未定义错误消息。

1

这就是你一直在寻找的解决方案:

我刚刚修复了它。

代码:

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

输出:

如果用户名存在,则显示原样。否则,用户名将包含字符串“登录”。


1

对我来说最安全且唯一有效的解决方案

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

或者一个简短的版本

<% (typeof user !== 'undefined' && typeof user.name !== 'undefined') ? user.name : '' %>

0

我曾经遇到过同样的问题,幸运的是,我发现JS中也有短路函数(我知道Ruby和其他一些语言中也有这种函数)。

在我的服务器/控制器端(这是来自Node.js/Express):

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

看到我做了什么吗?在可能未定义的变量(即request.session.survey_result对象,可能具有表单数据,也可能没有)之后跟随的&&是JS中的短路符号。它的作用是仅在&&左侧部分不为undefined时才评估其后面的部分。当左侧部分为undefined时,它也不会抛出错误。它只是忽略它。

现在,在我的模板中(记住我将对象req.session.survey_result_survey作为survey_result传递给我的视图),然后我呈现字段:

<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>

我在那里也使用了短路,只是为了安全起见。

当我尝试以前建议的方式时,只是:

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

有时候,它仍然会尝试评估IF语句内的属性...也许有人可以解释一下为什么?
此外,我想更正之前示例中使用单引号的undefined。因为该条件永远不会评估为true,你正在将一个字符串值'undefined'与数据类型undefined进行比较。

0

我在某个地方读到使用locals不是完美的,所以我想出了类似这样的解决方法,例如:

在Express文件中:

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

在 EJS 模板中:

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

0

我想使用一个模板并有条件地显示更多的数据。

我尝试了<? more_data = more_data ?? false ?>,这是我在TypeScript(和其他支持它的语言)中喜欢做的方式。这将在PHP中修复它,因为PHP在设置时间上非常容忍空值,但在读取时间上不太容忍(效果很好)。

在这里阅读了一些答案后...

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


0

我想出了另一种解决方案。

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

希望这能有所帮助。


1
你可以将两个条件合并为一个判断:if (user && user.name) - Jonathan Brizio

0
你可以使用这个技巧:
user.name // stops code execution,if user is undefined
(scope.user||0).name // === undefined

其中scope是用户的父对象


0
如果您计划经常使用相同的对象,可以使用以下类似于函数的代码:
<% 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;
} %>

用法:

<% if(userObj('name')){
    <h2><%= userObj('name') %></h2>
} %>

-2

我在Joe Andrieu的博客上找到了我认为更好的解决方案:

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

这种方法适用于更多的情况(即当您需要检查单个属性是否存在时)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接