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.

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


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



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

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

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.


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>

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) { %>

<% } %>

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.


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.


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


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

0

Mam inne rozwiązanie.

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

Mam nadzieję, że to pomoże.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.