Quelle est la bonne façon de vérifier l'existence d'une variable dans un modèle EJS (à l'aide d'ExpressJS)?

122

Sur la page github EJS, il y a un et un seul exemple simple: https://github.com/visionmedia/ejs

Exemple

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

Cela semble vérifier l'existence d'une variable nommée user, et si elle existe, faites certaines choses. Duh, non?

Ma question est, pourquoi dans le monde Node lancerait-il une ReferenceError si la variable utilisateur n'existe pas? Cela rend l'exemple ci-dessus inutile. Quelle est la manière appropriée de vérifier l'existence d'une variable? Dois-je utiliser un mécanisme try / catch et récupérer cette 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)

Je comprends que je pourrais faire disparaître cette erreur en ajoutant simplement une variable locale "utilisateur" dans mon code serveur, mais le point essentiel ici est que je veux vérifier l'existence de telles variables au moment de l'exécution en utilisant votre tous les jours si / sinon modèle de type nullcheck. Une exception pour une variable qui n'existe pas me semble ridicule.

Aashay Desai
la source

Réponses:

149

De la même manière que vous le feriez avec n'importe quoi dans js, typeof foo == 'undefined'ou puisque "locals" est le nom de l'objet qui les contient, vous pouvez le faire if (locals.foo). C'est juste brut js: p

tjholowaychuk
la source
3
Je commence à me demander si j'ai un plus gros problème entre les mains. Cela génère également une erreur de référence: <% alert ('test'); %>
Aashay Desai
1
@Aashay alertfait partie d'un windowobjet de navigateur et n'est pas disponible dans node.js. L'alternative est console.log, même si je ne sais pas si elle est disponible dans un modèle ejs à moins que vous ne la transmettiez via locals.
Zikes
2
@Zikes Dans ce cas, je recherche spécifiquement EJS, donc c'est sur la page du navigateur. Mais, comme TJ l'a dit, typeof foo == 'undefined' fonctionne. J'ai appris que je pourrais aussi ajouter un simple !! foo si foo a été défini mais est nul ou vide.
Aashay Desai
21
Y a-t-il un raccourci pour cela? Pourquoi EJS n'honore-t-il pas simplement le cas if (foo)?
mattdlockyer
5
if (locals.user){ }FTW
s2t2
26

Essayez de faire précéder la variable de locals

Exemple: if(locals.user){}

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

 // Your logic goes here 

<% } %>
Anirudh
la source
13

Vous pouvez créer un assistant de vue qui vérifie "obj === void 0", celui-ci est pour 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;
}

Ensuite, utilisez-le dans la vue comme

<%- get('deep.nested.non.existent.value') %>  //returns: null
<%- get('deep.nested.non.existent.value', "default value") %> //returns: default value
Paulius Uza
la source
3
Je ne sais pas pourquoi cela a été critiqué, c'est plutôt élégant à mon avis.
joseym
Quelle est la différence entre <%=et <%-?
NobleUplift
2
@NobleUplift Selon la documentation , sous "Tags": <%=HTML échappe d'abord la valeur; <%-renvoie la valeur non échappée. Donc <b>deviendrait une balise en gras lors de l'utilisation <%-, mais simplement le texte "<b>" lors de l'utilisation<%=
Matheus Avellar
Je vous remercie! Je n'avais aucune idée de <% - était même une balise valide.
NobleUplift
13

Pour vérifier si l'utilisateur est défini, vous devez le faire:

<% if (this.user) { %>
   here, user is defined
<% } %>
HenioJR
la source
3
Cela ne fonctionne pas dans la bibliothèque EJS la plus à jour (1.0.0). Bien que JavaScript soit valide, EJS refusera d'agir comme prévu.
Axoren
5
Ça ne marche pas pour moi. Même si j'ai défini foo, la clause else est toujours évaluée. Testé avec EJS 2.3.4 EDIT: utilisation localsà la place des thistravaux
X_Trust
8

J'ai rencontré le même problème en utilisant node.js avec mangouste / express / ejs lors de la création d'une relation entre 2 collections avec populate () de mangouste, dans ce cas admins.user_id existait mais était lié à un user._id inexistant.
Donc, je n'ai pas pu trouver pourquoi:

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

échouait avec "Impossible de lire la propriété 'nom' de null" Ensuite, j'ai remarqué que je devais faire la vérification comme ceci:

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

J'avais besoin de vérifier le "conteneur" de 'nom', donc ça a marché!
Après cela, cela a fonctionné de la même manière:

if ( !users.user_id ) ...  

J'espère que ça aide.

aesede
la source
Bref, je ne peux pas croire qu'il y ait si peu de documentation officielle sur EJS ... ils ne mettent pas à jour leur documentation depuis 2010 !!!
aesede le
3

Je suis venu sur cette page pour obtenir une réponse, mais j'ai proposé une syntaxe en ligne plus courte, à savoir:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>
Adam Boostani
la source
1
Ceci est dangereux à utiliser, car si l'objet 'user' n'a pas de propriété 'name', le rendu ejs échouera.
Marko Rochevski
1

Pour votre ifrelevé, vous devez utiliser typeof:

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

<% } %>
Fabien Thétis
la source
0

Ce que je fais, c'est juste passer un objet par défaut que j'appelle 'data' = '' et le passer à tous mes modèles ejs. Si vous avez besoin de transmettre des données réelles au modèle ejs, ajoutez-les en tant que propriété de l'objet 'data'.

De cette façon, l'objet 'data' est toujours défini et vous n'obtenez jamais de message d'erreur indéfini, même si la propriété 'data' existe dans votre modèle ejs mais pas dans votre route express de nœud.

Robert Brax
la source
0

J'ai eu le même problème, et heureusement, j'ai trouvé qu'il y avait aussi une fonction de court-circuit dans JS (je savais qu'il y en avait une en Ruby et dans d'autres langues).

Du côté de mon serveur / contrôleur (cela vient de Node.js / Express):

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

Regarde ce que j'ai fait là? Le && qui suit une variable éventuellement indéfinie (c'est-à-dire un request.session.survey_resultobjet, qui pourrait ou non avoir des données de forme) est la notation de court-circuit dans JS. Il évalue uniquement la partie qui suit le && si la partie à gauche du && n'est PAS indéfinie. Il ne génère pas non plus d'erreur lorsque la partie gauche EST undefined. Il l'ignore tout simplement.

Maintenant, dans mon modèle (rappelez-vous que j'ai passé l'objet req.session.survey_result_surveyobjet à ma vue en tant que survey_result), puis j'ai rendu les champs comme:

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

J'ai utilisé le court-circuit là aussi, juste pour la sécurité.

Lorsque je l'ai essayé avec les méthodes suggérées précédemment, il suffit de:

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

Parfois, il essayait toujours d'évaluer les propriétés dans l'instruction IF ... Peut-être que quelqu'un peut offrir une explication sur pourquoi?

En outre, je voulais corriger cela undefineddoit être sans les guillemets simples, comme je l'ai vu dans les exemples précédents. Parce que la condition ne sera jamais évaluée true, car vous comparez une valeur String 'undefined'avec un type de données undefined.

Yekatjarina Aljaksandrayna Shu
la source
0

Vous pouvez utiliser cette astuce:

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

où scope est l'objet parent de l'utilisateur

Alex Szücs
la source
0

si vous prévoyez d'utiliser souvent le même objet, vous pouvez utiliser une fonction comme celle-ci:

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

usage:

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

J'ai trouvé une autre solution.

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

J'espère que ça aide.

omar
la source