Qual é a maneira correta de verificar a existência de variáveis ​​em um modelo EJS (usando ExpressJS)?

121

Na página do github EJS, há um e apenas um exemplo simples: https://github.com/visionmedia/ejs

Exemplo

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

Isso parece estar verificando a existência de uma variável chamada user e, se ela existir, faça algumas coisas. Duh, certo?

Minha pergunta é: por que o Node lançaria um ReferenceError se a variável de usuário não existe? Isso torna o exemplo acima inútil. Qual é a maneira apropriada de verificar a existência de uma variável? Devo usar um mecanismo try / catch e capturar esse 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)

Eu entendo que eu poderia fazer esse erro desaparecer simplesmente adicionando uma variável local de "usuário" no meu código de servidor, mas o ponto principal aqui é que eu quero verificar a existência de tais variáveis ​​em tempo de execução usando seu every day if / else padrão de tipo nullcheck. Uma exceção para uma variável que não existe parece ridícula para mim.

Aashay Desai
fonte

Respostas:

149

Você pode fazer da mesma forma que faria com qualquer coisa em js, typeof foo == 'undefined'ou como "locals" é o nome do objeto que os contém if (locals.foo). É apenas js: p bruto

Tjholowaychuk
fonte
3
Estou começando a me perguntar se tenho um problema maior em minhas mãos. Isso também gera um erro de referência: <% alert ('test'); %>
Aashay Desai
1
@Aashay alerté parte do windowobjeto de um navegador e não está disponível em node.js. A alternativa é console.log, embora eu não saiba se ele está disponível em um modelo ejs, a menos que você passe por locals.
Zikes
2
@Zikes Neste caso, estou procurando especificamente por EJS, então está na página do navegador. Mas, como TJ disse, typeof foo == 'undefined' funciona. Aprendi que também posso adicionar um !! foo simples se foo tiver sido definido, mas for nulo ou vazio.
Aashay Desai
21
Existe um atalho para isso? Por que o EJS simplesmente não honra o caso if (foo)?
mattdlockyer de
5
if (locals.user){ }FTW
s2t2
26

Tente prefixar a variável com locals

Exemplo: if(locals.user){}

spencer.sm
fonte
23
<% if (locals.user) { %>

 // Your logic goes here 

<% } %>
Anirudh
fonte
13

Você pode criar um assistente de visualização que verifica "obj === void 0", este é para 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;
}

Em seguida, use-o na vista como

<%- get('deep.nested.non.existent.value') %>  //returns: null
<%- get('deep.nested.non.existent.value', "default value") %> //returns: default value
Paulius Uza
fonte
3
não sei por que isso foi rejeitado, é bastante elegante na minha opinião.
Joseym
Qual é a diferença entre <%=e <%-?
NobleUplift
2
@NobleUplift De acordo com a documentação , em "Tags": <%=HTML escapa o valor primeiro; <%-produz o valor sem escape. Então <b>se tornaria uma tag em negrito ao usar <%-, mas simplesmente o texto "<b>" ao usar<%=
Matheus Avellar
Obrigado! Eu não tinha ideia de que <% - era até mesmo uma tag válida.
NobleUplift
13

Para verificar se o usuário está definido, você precisa fazer isso:

<% if (this.user) { %>
   here, user is defined
<% } %>
HenioJR
fonte
3
Isso não funciona na biblioteca EJS mais atualizada (1.0.0). Embora seja um Javascript válido, o EJS se recusará a agir conforme o esperado.
Axoren
5
Nao funciona para mim. Mesmo que eu tenha definido foo, a cláusula else ainda é avaliada. Testado com EJS 2.3.4 EDIT: usando localsno local de thistrabalho
X_Trust
8

Eu encontrei o mesmo problema usando node.js com mongoose / express / ejs ao fazer uma relação entre 2 coleções junto com populate () do mongoose, neste caso admins.user_id existia, mas estava relacionado a um users._id inexistente.
Então, não consegui descobrir o porquê:

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

estava falhando com "Não é possível ler a propriedade 'nome' de nulo" Então percebi que precisava fazer a verificação assim:

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

Eu precisava verificar o "container" de 'name', então funcionou!
Depois disso, funcionou da mesma forma:

if ( !users.user_id ) ...  

Espero que ajude.

Aesede
fonte
Enfim, não acredito que existam tão poucas documentações oficiais sobre EJS ... eles não atualizam sua documentação desde 2010 !!!
aesede
3

Vim a esta página para obter uma resposta, mas descobri uma sintaxe in-line mais curta para ela, que é:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>
Adam Boostani
fonte
1
Isso é perigoso de usar, pois se o objeto 'usuário' não tiver uma propriedade 'nome', a renderização ejs falhará.
Marko Rochevski
1

Para sua ifdeclaração, você precisa usar typeof:

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

<% } %>
Fabien Thetis
fonte
0

O que eu faço é apenas passar um objeto padrão que chamo de 'dados' = '' e passá-lo para todos os meus modelos ejs. Se você precisar passar dados reais para o template ejs, adicione-os como propriedade do objeto 'data'.

Desta forma, o objeto 'data' é sempre definido e você nunca obtém mensagem de erro indefinida, mesmo que a propriedade 'data' exista em seu modelo ejs, mas não em sua rota expressa de nó.

Robert Brax
fonte
0

Eu tive o mesmo problema e, felizmente, descobri que também há uma função de curto-circuito em JS (eu sabia que havia uma em Ruby e algumas outras linguagens).

No meu servidor / controlador (isso é do Node.js / Express):

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

Veja o que eu fiz lá? O && que segue após uma variável possivelmente indefinida (ou seja request.session.survey_result, objeto, que pode ou não ter dados de formulário) é a notação de curto-circuito em JS. O que ele faz é apenas avaliar a parte que segue o && se a parte à esquerda do && NÃO for indefinida. Ele também não lança um erro quando a parte esquerda ESTÁ undefined. Ele simplesmente o ignora.

Agora, em meu modelo (lembre-se de que passei o objeto req.session.survey_result_surveyobjeto para minha visualização como survey_result) e renderizei os campos como:

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

Eu usei curto-circuito lá também, apenas por segurança.

Quando experimentei com as formas sugeridas anteriormente, apenas:

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

Às vezes, ele ainda tentaria avaliar as propriedades dentro da instrução IF ... Talvez alguém possa oferecer uma explicação do porquê?

Além disso, queria corrigir que undefinedprecisa ser sem as aspas simples, como vi feito em exemplos anteriores. Porque a condição nunca será avaliada truecomo, pois você está comparando um valor String 'undefined'com um tipo de dados undefined.

Yekatjarina Aljaksandrayna Shu
fonte
0

Você pode usar este truque:

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

onde o escopo é o objeto pai do usuário

Alex Szücs
fonte
0

se você planeja usar o mesmo objeto com frequência, pode usar uma função como esta:

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

uso:

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

Eu encontrei outra solução.

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

Eu espero que isso ajude.

omar
fonte