Qual è il modo corretto per verificare l'esistenza di una variabile in un modello EJS (utilizzando ExpressJS)?


121

Nella pagina github di EJS, c'è un solo semplice esempio: https://github.com/visionmedia/ejs

Esempio

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

Questo sembra controllare l'esistenza di una variabile denominata user e, se esiste, fare alcune cose. Duh, giusto?

La mia domanda è: perché nel mondo Node dovrebbe lanciare un ReferenceError se la variabile utente non esiste? Ciò rende inutile l'esempio precedente. Qual è il modo appropriato per verificare l'esistenza di una variabile? Devo usare un meccanismo try / catch e prendere quell'eccezione 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)

Capisco che potrei fare in modo che questo errore scompaia semplicemente aggiungendo una variabile locale "utente" nel codice del mio server, ma il punto qui è che voglio verificare l'esistenza di tali variabili in fase di esecuzione utilizzando ogni giorno il tuo if / else modello di tipo nullcheck. Un'eccezione per una variabile che non esiste mi sembra ridicola.

Risposte:


149

Lo stesso modo in cui lo faresti con qualsiasi cosa in js, typeof foo == 'undefined'o poiché "locals" è il nome dell'oggetto che li contiene, puoi farlo if (locals.foo). È solo js grezzo: p


3
Comincio a chiedermi se ho un problema più grande tra le mani. Anche questo genera un errore di riferimento: <% alert ('test'); %>
Aashay Desai

1
@Aashay alertfa parte di un windowoggetto del browser e non è disponibile in node.js. L'alternativa è console.log, anche se non so se è disponibile in un modello ejs a meno che non lo passi tramite locals.
Zikes

2
@Zikes In questo caso sto cercando specificamente EJS, quindi è sulla pagina del browser. Ma, come ha detto TJ, typeof foo == 'undefined' funziona. Ho imparato che potrei anche aggiungere un semplice !! foo se foo è stato definito ma è nullo o vuoto.
Aashay Desai,

21
C'è una scorciatoia per questo? Perché EJS non rispetta semplicemente il caso if (foo)?
mattdlockyer

5
if (locals.user){ }FTW
S2T2

26

Prova ad anteporre la variabile con locals

Esempio: if(locals.user){}


23
<% if (locals.user) { %>

 // Your logic goes here 

<% } %>

13

Puoi creare un view helper che controlli "obj === void 0", questo è per 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;
}

Quindi usalo nella vista come

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

3
Non sono sicuro del motivo per cui questo è stato downvoted, è piuttosto elegante secondo me.
joseym

Qual'è la differenza tra <%=e <%-?
NobleUplift

2
@NobleUplift Come da documentazione , sotto "Tag": <%=HTML prima sfugge il valore; <%-restituisce il valore senza caratteri di escape. Quindi <b>diventerebbe un tag in grassetto quando si utilizza <%-, ma semplicemente il testo "<b>" quando si utilizza<%=
Matheus Avellar

Grazie! Non ne avevo idea <% - era anche un tag valido.
NobleUplift

13

Per verificare se l'utente è definito, devi farlo:

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

3
Questo non funziona nella libreria EJS più aggiornata (1.0.0). Sebbene Javascript sia valido, EJS rifiuterà di agire come previsto.
Axoren

5
Non funziona per me. Anche se ho definito foo, la clausola else viene ancora valutata. Testato con EJS 2.3.4 EDIT: utilizzo localsal posto dei thislavori
X_Trust

8

Ho riscontrato lo stesso problema utilizzando node.js con mongoose / express / ejs quando si crea una relazione tra 2 raccolte insieme a mongoose's populate (), in questo caso admins.user_id esisteva ma era correlato a un users._id inesistente.
Quindi, non sono riuscito a trovare il motivo:

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

stava fallendo con "Impossibile leggere la proprietà 'nome' di null" Quindi ho notato che dovevo fare il controllo in questo modo:

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

Avevo bisogno di controllare il "contenitore" di "nome", quindi ha funzionato!
Dopodiché, ha funzionato allo stesso modo:

if ( !users.user_id ) ...  

Spero che sia d'aiuto.


Comunque, non posso credere che ci sia così poca documentazione ufficiale su EJS ... non aggiornano la loro documentazione dal 2010 !!!
aesede

3

Sono venuto in questa pagina per una risposta, ma ho trovato una sintassi in linea più breve che è:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>

1
Questo è pericoloso da usare, perché se l'oggetto 'utente' non ha una proprietà 'nome', il rendering di ejs fallirà.
Marko Rochevski

1

Per la tua ifdichiarazione devi usare typeof:

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

<% } %>

0

Quello che faccio è semplicemente passare un oggetto predefinito che chiamo 'data' = '' e passarlo a tutti i miei modelli ejs. Se devi passare dati reali al modello ejs, aggiungili come proprietà dell'oggetto 'data'.

In questo modo, l'oggetto "data" è sempre definito e non si ottiene mai un messaggio di errore non definito, anche se la proprietà di "dati" esiste nel modello ejs ma non nella route express del nodo.


0

Ho avuto lo stesso problema e, fortunatamente, ho scoperto che c'è anche una funzione di cortocircuito in JS (sapevo che ce n'era una in Ruby e in alcune altre lingue).

Sul mio lato server / controller (questo è da Node.js / Express):

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

Vedi cosa ho fatto lì? Il && che segue dopo una variabile possibilmente indefinita (cioè un request.session.survey_resultoggetto, che potrebbe o non potrebbe avere dati di forma) è la notazione di cortocircuito in JS. Quello che fa è valutare solo la parte che segue && se la parte a sinistra di && NON è indefinita. Inoltre non genera un errore quando la parte sinistra È undefined. Semplicemente lo ignora.

Ora, nel mio modello (ricorda che ho passato l'oggetto req.session.survey_result_surveyoggetto alla mia vista come survey_result) e poi ho reso i campi come:

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

Ho usato il cortocircuito anche lì, solo per sicurezza.

Quando l'ho provato con i modi suggeriti in precedenza, basta:

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

A volte, proverebbe comunque a valutare le proprietà all'interno dell'istruzione IF ... Forse qualcuno può offrire una spiegazione sul perché?

Inoltre, volevo correggere che undefineddeve essere senza le virgolette singole, come ho visto negli esempi precedenti. Perché la condizione non verrà mai valutata true, poiché stai confrontando un valore String 'undefined'con un tipo di dati undefined.


0

Puoi usare questo trucco:

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

dove scope è l'oggetto genitore dell'utente


0

se prevedi di usare spesso lo stesso oggetto, potresti usare una funzione come questa:

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

utilizzo:

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

0

Ho trovato un'altra soluzione.

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

Spero che aiuti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.