¿Cuál es la forma correcta de verificar la existencia de una variable en una plantilla EJS (usando ExpressJS)?

121

En la página de github de EJS, hay un solo ejemplo simple: https://github.com/visionmedia/ejs

Ejemplo

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

Esto parece estar verificando la existencia de una variable llamada usuario, y si existe, haga algunas cosas. Duh, ¿verdad?

Mi pregunta es, ¿por qué en el mundo Node lanzaría un ReferenceError si la variable de usuario no existe? Esto hace que el ejemplo anterior sea inútil. ¿Cuál es la forma adecuada de comprobar la existencia de una variable? ¿Se espera que use un mecanismo de prueba / captura y agarre ese 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)

Entiendo que podría hacer desaparecer este error simplemente agregando una variable local de "usuario" en el código de mi servidor, pero el punto aquí es que quiero verificar la existencia de tales variables en tiempo de ejecución usando su if / else todos los días patrón de tipo nullcheck. Una excepción para una variable que no existe me parece ridícula.

Aashay Desai
fuente

Respuestas:

149

De la misma manera que lo haría con cualquier cosa en js, typeof foo == 'undefined'o como "locals" es el nombre del objeto que los contiene, puede hacerlo if (locals.foo). Es solo js sin formato: p

tjholowaychuk
fuente
3
Empiezo a preguntarme si tengo un problema mayor en mis manos. Esto también arroja un Error de referencia: <% alert ('prueba'); %>
Aashay Desai
1
@Aashay alertes parte del windowobjeto de un navegador y no está disponible en node.js. La alternativa es console.log, aunque no sé si está disponible en una plantilla ejs a menos que la pase a través de locals.
Zikes
2
@Zikes En este caso, estoy buscando específicamente EJS, por lo que está en la página del navegador. Pero, como dijo TJ, typeof foo == 'undefined' funciona. Aprendí que también podría agregar un simple !! foo si se ha definido foo pero es nulo o vacío.
Aashay Desai
21
¿Existe una abreviatura para esto? ¿Por qué EJS simplemente no respeta el caso if (foo)?
mattdlockyer
5
if (locals.user){ }FTW
s2t2
26

Intente anteponer la variable con locals

Ejemplo: if(locals.user){}

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

 // Your logic goes here 

<% } %>
Anirudh
fuente
13

Puede crear un asistente de vista que busque "obj === void 0", este es 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;
}

Luego úsalo en la vista como

<%- get('deep.nested.non.existent.value') %>  //returns: null
<%- get('deep.nested.non.existent.value', "default value") %> //returns: default value
Paulius Uza
fuente
3
No estoy seguro de por qué fue rechazado, es bastante elegante en mi opinión.
joseym
¿Cuál es la diferencia entre <%=y <%-?
NobleUplift
2
@NobleUplift Según la documentación , en "Etiquetas": <%=HTML escapa el valor primero; <%-emite el valor no escapado. Entonces <b>se convertiría en una etiqueta en negrita cuando se usa <%-, pero simplemente el texto "<b>" cuando se usa<%=
Matheus Avellar
¡Gracias! No tenía idea de <%, incluso era una etiqueta válida.
NobleUplift
13

Para verificar si el usuario está definido, debe hacer eso:

<% if (this.user) { %>
   here, user is defined
<% } %>
HenioJR
fuente
3
Esto no funciona en la biblioteca EJS más actualizada (1.0.0). Aunque Javascript es válido, EJS se negará a actuar como se esperaba.
Axoren
5
No me funciona. A pesar de que he definido foo, la cláusula else todavía se evalúa. Probado con EJS 2.3.4 EDIT: uso localsen lugar de thistrabajos
X_Trust
8

Me encontré con el mismo problema al usar node.js con mongoose / express / ejs al establecer una relación entre 2 colecciones junto con mongoose's populate (), en este caso existía admins.user_id pero estaba relacionado con un users._id inexistente.
Entonces, no pude encontrar por qué:

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

estaba fallando con "No se puede leer la propiedad 'nombre' de nulo" Entonces noté que necesitaba hacer la verificación de esta manera:

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

Necesitaba comprobar el "contenedor" de 'nombre', ¡así que funcionó!
Después de eso, esto funcionó igual:

if ( !users.user_id ) ...  

Espero eso ayude.

aesede
fuente
De todos modos, no puedo creer que haya tan poca documentación oficial sobre EJS ... ¡¡¡no actualizan su documentación desde 2010 !!!
aesede
3

Vine a esta página para obtener una respuesta, pero se me ocurrió una sintaxis en línea más corta que es:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>
Adam Boostani
fuente
1
Esto es peligroso de usar, porque si el objeto 'usuario' no tiene una propiedad de 'nombre', la representación de ejs fallará.
Marko Rochevski
1

Para su ifestado de cuenta, debe utilizar typeof:

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

<% } %>
Fabien Thetis
fuente
0

Lo que hago es simplemente pasar un objeto predeterminado al que llamo 'data' = '' y pasarlo a todas mis plantillas ejs. Si necesita pasar datos reales a la plantilla ejs, agréguelos como propiedad del objeto 'datos'.

De esta manera, el objeto 'datos' siempre se define y nunca obtiene un mensaje de error indefinido, incluso si la propiedad de 'datos' existe en su plantilla ejs pero no en su ruta expresa de nodo.

Robert Brax
fuente
0

Tuve el mismo problema y, afortunadamente, descubrí que también hay una función de cortocircuito en JS (sabía que había una en Ruby y en algunos otros idiomas).

En mi servidor / lado del controlador (esto es de Node.js / Express):

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

¿Ves lo que hice ahí? El && que sigue a una variable posiblemente indefinida (es decir,request.session.survey_result , un objeto, que puede tener o no datos de formulario) es la notación de cortocircuito en JS. Lo que hace es solo evaluar la parte que sigue a && si la parte a la izquierda de && NO está indefinida. Tampoco arroja un error cuando la parte izquierda ESundefined . Simplemente lo ignora.

Ahora, en mi plantilla (recuerde que pasé el objeto req.session.survey_result_surveyobjeto a mi vista como survey_result) y luego rendericé los 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>

También utilicé el cortocircuito allí, solo para resguardos.

Cuando lo probé con las formas sugeridas anteriormente, simplemente:

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

A veces, todavía intentaría evaluar las propiedades dentro de la declaración IF ... ¿Quizás alguien pueda ofrecer una explicación de por qué?

Además, quería corregir eso undefineddebe ser sin las comillas simples, como vi en ejemplos anteriores. Porque la condición nunca se evaluará a true, ya que está comparando un valor de cadena 'undefined'con un tipo de datos undefined.

Yekatjarina Aljaksandrayna Shu
fuente
0

Puedes usar este truco:

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

donde el alcance es el objeto principal del usuario

Alex Szücs
fuente
0

Si planea usar el mismo objeto con frecuencia, puede usar una función 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
fuente
0

Se me ocurrió otra solución.

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

Espero que esto ayude.

omar
fuente