Как правильно проверить наличие переменной в шаблоне EJS (с помощью ExpressJS)?

122

На странице Github EJS есть один-единственный простой пример: https://github.com/visionmedia/ejs

пример

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

Кажется, это проверяет наличие переменной с именем 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)

Я понимаю, что могу устранить эту ошибку, просто добавив локальную переменную "user" в код моего сервера, но все дело в том, что я хочу проверять наличие таких переменных во время выполнения, используя ваш каждый день if / else образец типа nullcheck. Мне кажется смешным исключение для несуществующей переменной.

Аашай Десаи
источник

Ответы:

149

Вы можете сделать это так же, как и с чем-либо в js, typeof foo == 'undefined'или, поскольку «locals» - это имя объекта, который их содержит if (locals.foo). Это просто необработанный js: p

tjholowaychuk
источник
3
Я начинаю задумываться, есть ли у меня более серьезная проблема. Это также вызывает эталонную ошибку: <% alert ('test'); %>
Aashay Desai
1
@Aashay alertявляется частью объекта браузера windowи недоступен в node.js. Альтернативой является console.log, хотя я не знаю, доступна ли она в шаблоне ejs, если вы не передадите ее через locals.
Zikes
2
@Zikes В данном случае я ищу именно EJS, так что он находится на странице браузера. Но, как сказал TJ, typeof foo == 'undefined' работает. Я узнал, что могу добавить простой !! foo, если foo был определен, но имеет значение null или пусто.
Aashay Desai
21
Есть ли это сокращение? Почему EJS просто не учитывает случай if (foo)?
mattdlockyer
5
if (locals.user){ }FTW
s2t2
26

Попробуйте добавить переменную с помощью locals

Пример: if(locals.user){}

spencer.sm
источник
23
<% if (locals.user) { %>

 // Your logic goes here 

<% } %>
Anirudh
источник
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>»<%=
Матеус
Спасибо! Я понятия не имел, что <% - это даже действительный тег.
NobleUplift
13

Чтобы проверить, определен ли пользователь, вам нужно сделать это:

<% if (this.user) { %>
   here, user is defined
<% } %>
HenioJR
источник
3
Это не работает в самой последней версии библиотеки EJS (1.0.0). Несмотря на то, что Javascript является действительным, EJS отказывается действовать должным образом.
Axoren
5
У меня не работает. Несмотря на то, что я определил foo, предложение else все еще оценивается. Протестировано с EJS 2.3.4 EDIT: использование localsвместо thisработ
X_Trust
8

Я столкнулся с той же проблемой, используя node.js с mongoose / express / ejs при установлении связи между двумя коллекциями вместе с mongoose populate (), в этом случае admins.user_id существовал, но был связан с несуществующим users._id.
Итак, я не мог понять, почему:

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

не удалось прочитать свойство 'name', равное нулю. Затем я заметил, что мне нужно выполнить проверку следующим образом:

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

Мне нужно было проверить "контейнер" имени, так что это сработало!
После этого все работало так же:

if ( !users.user_id ) ...  

Надеюсь, поможет.

aesede
источник
В любом случае, не могу поверить, что официальной документации по EJS так мало ... они не обновляют свою документацию с 2010 года !!!
aesede
3

Пришел на эту страницу за ответом, но я придумал для него более короткий встроенный синтаксис:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>
Адам Бустани
источник
1
Это опасно использовать, потому что, если объект user не имеет свойства name, рендеринг ejs завершится ошибкой.
Марко Рочевски
1

Для ifвыписки вам необходимо использовать typeof:

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

<% } %>
Фабьен Фетис
источник
0

Я просто передаю объект по умолчанию, который я называю 'data' = '', и передаю его всем моим шаблонам ejs. Если вам нужно передать реальные данные в шаблон ejs, добавьте их как свойство объекта data.

Таким образом, объект 'data' всегда определяется, и вы никогда не получите неопределенное сообщение об ошибке, даже если свойство 'data' существует в вашем шаблоне 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. Он оценивает только ту часть, которая следует за &&, если часть слева от && НЕ определена. Также не выдает ошибку, когда левая часть ЕСТЬ 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>
} %>
SwiftNinjaPro
источник
0

Я придумал другое решение.

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

Надеюсь, это поможет.

Omar
источник