Jaki jest właściwy sposób sprawdzenia istnienia zmiennej w szablonie EJS (przy użyciu ExpressJS)?

121

Na stronie github EJS jest jeden i tylko jeden prosty przykład: https://github.com/visionmedia/ejs

Przykład

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

Wygląda na to, że sprawdza istnienie zmiennej o nazwie user, a jeśli istnieje, zrób coś. Duh, prawda?

Moje pytanie brzmi: dlaczego na świecie Node miałby wyrzucać ReferenceError, jeśli zmienna użytkownika nie istnieje? To sprawia, że ​​powyższy przykład jest bezużyteczny. Jaki jest właściwy sposób sprawdzania istnienia zmiennej? Czy mam użyć mechanizmu try / catch i pobrać ten błąd 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)

Rozumiem, że mógłbym usunąć ten błąd, po prostu dodając zmienną lokalną „user” w kodzie mojego serwera, ale chodzi o to, że chcę sprawdzić istnienie takich zmiennych w czasie wykonywania, używając każdego dnia, jeśli / else wzorzec typu nullcheck. Wyjątek dla zmiennej, która nie istnieje, wydaje mi się śmieszny.

Aashay Desai
źródło

Odpowiedzi:

149

W ten sam sposób zrobiłbyś to z czymkolwiek w js, typeof foo == 'undefined'lub ponieważ „locals” to nazwa obiektu, który je zawiera, możesz to zrobić if (locals.foo). To tylko surowy js: s

tjholowaychuk
źródło
3
Zaczynam się zastanawiać, czy mam większy problem na rękach. Powoduje to również zgłoszenie błędu odwołania: <% alert ('test'); %>
Aashay Desai
1
@Aashay alertjest częścią obiektu przeglądarki windowi nie jest dostępne w node.js. Alternatywą jest console.log, chociaż nie wiem, czy jest dostępny w szablonie ejs, chyba że przekażesz go przez locals.
Zikes
2
@Zikes W tym przypadku szukam specjalnie dla EJS, więc jest na stronie przeglądarki. Ale, jak powiedział TJ, typeof foo == 'undefined' działa. Dowiedziałem się, że mogę również dodać proste !! foo, jeśli foo zostało zdefiniowane, ale jest puste lub puste.
Aashay Desai
21
Czy jest na to skrót? Dlaczego EJS po prostu nie honoruje przypadku if (foo)?
mattdlockyer
5
if (locals.user){ }FTW
s2t2
26

Spróbuj poprzedzić zmienną locals

Przykład: if(locals.user){}

spencer.sm
źródło
23
<% if (locals.user) { %>

 // Your logic goes here 

<% } %>
Anirudh
źródło
13

Możesz utworzyć pomocnika widoku, który sprawdza „obj === void 0”, ten jest przeznaczony dla 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;
}

Następnie użyj go w widoku jak

<%- get('deep.nested.non.existent.value') %>  //returns: null
<%- get('deep.nested.non.existent.value', "default value") %> //returns: default value
Paulius Uza
źródło
3
Nie jestem pewien, dlaczego został odrzucony, moim zdaniem jest raczej elegancki.
joseym
Jaka jest różnica między <%=i <%-?
NobleUplift
2
@NobleUplift Zgodnie z dokumentacją , w sekcji „Tagi”: <%=HTML zmienia znaczenie jako pierwszy; <%-wyświetla wartość bez zmiany znaczenia. Tak więc <b>podczas używania stałoby się pogrubioną etykietą <%-, ale po prostu tekst „<b>” podczas używania<%=
Matheus Avellar
Dziękuję Ci! Nie miałem pojęcia, że ​​<% - był nawet prawidłowym tagiem.
NobleUplift
13

Aby sprawdzić, czy użytkownik jest zdefiniowany, musisz to zrobić:

<% if (this.user) { %>
   here, user is defined
<% } %>
HenioJR
źródło
3
Nie działa to w najbardziej aktualnej bibliotece EJS (1.0.0). Chociaż poprawny Javascript, EJS odmówi działania zgodnie z oczekiwaniami.
Axoren
5
Nie działa na mnie. Mimo że zdefiniowałem foo, klauzula else jest nadal oceniana. Testowane z EJS 2.3.4 EDIT: używanie localszamiast thispracy
X_Trust,
8

Natknąłem się na ten sam problem, używając node.js z mongoose / express / ejs podczas tworzenia relacji między 2 kolekcjami razem z populate () z mongoose, w tym przypadku admins.user_id istniał, ale był powiązany z nieistniejącym użytkownikiem ._id.
Nie mogłem więc znaleźć powodu:

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

wystąpił błąd „Nie można odczytać nazwy właściwości” o wartości null ”Następnie zauważyłem, że muszę sprawdzić, jak to zrobić:

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

Musiałem sprawdzić „kontener” „name”, więc zadziałało!
Potem zadziałało tak samo:

if ( !users.user_id ) ...  

Mam nadzieję, że to pomoże.

aesede
źródło
W każdym razie, nie mogę uwierzyć, że jest tak mało oficjalnej dokumentacji na temat EJS ... nie aktualizują swojej dokumentacji od 2010 roku !!!
koniec
3

Przyszedłem na tę stronę, aby uzyskać odpowiedź, ale wymyśliłem krótszą składnię wbudowaną, która jest:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>
Adam Boostani
źródło
1
Jest to niebezpieczne w użyciu, ponieważ jeśli obiekt „user” nie ma właściwości „name”, renderowanie ejs zakończy się niepowodzeniem.
Marko Rochevski
1

Do swojego ifoświadczenia musisz użyć typeof:

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

<% } %>
Fabien Thetis
źródło
0

Po prostu przekazuję domyślny obiekt, który nazywam 'data' = '' i przekazuję go do wszystkich moich szablonów ejs. Jeśli chcesz przekazać prawdziwe dane do szablonu ejs, dodaj je jako właściwość obiektu „data”.

W ten sposób obiekt 'data' jest zawsze zdefiniowany i nigdy nie otrzymasz niezdefiniowanego komunikatu o błędzie, nawet jeśli właściwość 'data' istnieje w szablonie ejs, ale nie w Twojej trasie ekspresowej węzła.

Robert Brax
źródło
0

Miałem ten sam problem i na szczęście odkryłem, że w JS jest również funkcja zwarcia (wiedziałem, że jest w Rubim i kilku innych językach).

Po stronie mojego serwera / kontrolera (pochodzi z Node.js / Express):

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

Widzisz co zrobiłem? Znak &&, który występuje po prawdopodobnie niezdefiniowanej zmiennej (tj. request.session.survey_resultObiekcie, który może mieć dane formularza lub nie) to notacja zwarcia w JS. Ocenia tylko część następującą po znaku &&, jeśli część po lewej stronie znaku && NIE jest niezdefiniowana. Nie zgłasza również błędu, gdy lewa część JEST undefined. Po prostu to ignoruje.

Teraz w moim szablonie (pamiętaj, że przekazałem obiekt req.session.survey_result_surveyobiekt do mojego widoku jako survey_result), a następnie wyrenderowałem pola jako:

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

Tam też zastosowałem zwarcie, tylko dla pewności.

Kiedy wypróbowałem to z wcześniej sugerowanymi sposobami, po prostu:

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

Czasami nadal próbowałby ocenić właściwości w wyrażeniu IF ... Może ktoś może zaoferować wyjaśnienie, dlaczego?

Chciałem również poprawić to, undefinedaby nie było pojedynczych cudzysłowów, jak widziałem w poprzednich przykładach. Ponieważ warunek nigdy nie da wartości true, ponieważ porównujesz wartość typu String 'undefined'z typem danych undefined.

Yekatjarina Aljaksandrayna Shu
źródło
0

Możesz użyć tej sztuczki:

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

gdzie zakres jest obiektem nadrzędnym użytkownika

Alex Szücs
źródło
0

jeśli planujesz często używać tego samego obiektu, możesz użyć takiej funkcji:

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

stosowanie:

<% if(userObj('name')){
    <h2><%= userObj('name') %></h2>
} %>
SwiftNinjaPro
źródło
0

Mam inne rozwiązanie.

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

Mam nadzieję, że to pomoże.

omar
źródło