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


121

在EJS github页面上,只有一个简单的示例:https : //github.com/visionmedia/ejs

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

这似乎是在检查是否存在名为user的变量,如果存在,请执行一些操作。h,对不对?

我的问题是,如果用户变量不存在,为什么世界上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来在运行时检查此类变量是否存在nullcheck类型模式。对于一个不存在的变量,异常对我来说似乎很可笑。

Answers:


149

您可以使用js中的任何方法来执行此操作typeof foo == 'undefined',或者由于“ locals”是包含它们的对象的名称,因此可以这样做if (locals.foo)。只是原始js:p


3
我开始怀疑我是否还有更大的问题。这也会引发参考错误:<%alert('test'); %>
Aashay Desai 2011年

1
@Aashay alert是浏览器window对象的一部分,在node.js中不可用。替代方法是console.log,尽管我不知道它是否可以在ejs模板中使用,除非您通过传入locals
Zikes 2011年

2
@Zikes在这种情况下,我专门针对EJS,因此它位于浏览器页面上。但是,就像TJ所说的那样,typeof foo =='undefined'有效。我了解到,如果已经定义了foo但它为null或为空,我也可以添加一个简单的!! foo。
Aashay Desai

21
有速记吗?EJS为什么不简单地接受if(foo)情况?
mattdlockyer

5
if (locals.user){ }FTW
s2t2



13

您可以创建一个视图助手来检查“ obj === void 0”,这是用于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;
}

然后在视图中使用它

<%- get('deep.nested.non.existent.value') %>  //returns: null
<%- get('deep.nested.non.existent.value', "default value") %> //returns: default value

3
不知道为什么不推荐,我认为它相当优雅。
joseym

<%=和之间有什么区别<%-
NobleUplift

2
@NobleUplift根据文档中 “标签”下的内容:<%=HTML首先转义该值;<%-输出未转义的值。因此<b>,使用时将变为粗体标签<%-,但使用时将变为文本“ <b>”<%=
Matheus Avellar

谢谢!我不知道<%-甚至是有效标签。
NobleUplift

13

要检查是否定义了用户,您需要执行以下操作:

<% if (this.user) { %>
   here, user is defined
<% } %>

3
这在最新的EJS库(1.0.0)中不起作用。尽管有效的Javascript,EJS仍将拒绝按预期运行。
Axoren

5
对我不起作用。即使我已经定义了foo,else子句仍然会被评估。经过EJS 2.3.4编辑测试:编辑:locals代替this工作
X_Trust '16

8

在2个集合与mongoose的populate()之间建立关系时,我遇到了使用node.js和mongoose / express / ejs的同一问题,在这种情况下admins.user_id存在但与不存在的users._id有关。
因此,找不到原因:

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

失败并显示“无法读取null的属性'名称'”,然后我注意到需要进行如下检查:

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

我需要检查“名称”的“容器”,所以它起作用了!
之后,它的工作原理相同:

if ( !users.user_id ) ...  

希望能帮助到你。


无论如何,不​​敢相信关于EJS的官方文档太少了……他们从2010年以来就没有更新其文档!!!
aesede 2015年



0

我要做的只是传递一个我称为'data'=''的默认对象,并将其传递给我的所有ejs模板。如果需要将真实数据传递给ejs模板,请将其添加为“数据”对象的属性。

这样,始终定义“数据”对象,即使ejs模板中存在“数据”属性,但在节点快速路由中不存在“数据”属性,也永远不会收到未定义的错误消息。


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中的短路符号。如果没有明确定义&&左边的部分,它只会评估&&后面的部分。当左部分是IS时,它也不会引发错误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,所以在将String值'undefined'与数据类型进行比较时undefined


0

您可以使用此技巧:

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

其中范围是用户的父对象


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

0

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

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

我希望这有帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.