Alexander Mills
Alexander Mills

Reputation: 100506

Global variable in template

I have this EJS template the represents the header of my web application. I am trying to access a global variable that I defined in my front-end Backbone application, but for some reason I am getting an error saying "appGlobal is not defined". The global variable in my front-end JavaScript like so:

appGlobal = {

        authorized: null,
        currentUser: null,
        env: null

    };

the template looks like so:

<header>
    <div>
        <div id="header-div-id">
            <% if(appGlobal && appGlobal.currentUser != null) { %>
            <div>Logged In As: <%= appGlobal.currentUser%></div>
            <button id="logout-button-id">Logout</button>
            <% } else { %>
            <div>You need to either register or login.</div>
            <% } %>
        </div>
    </div>
</header>
  1. I believe the reason why appGlobal is not defined in the template
    is because the template is rendered server-side and not client-side; and appGlobal is a clientside global.
  2. However, this code should still check to see if appGlobal is defined, so I don't see why it's throwing an error???
  3. if I change the template to use window.appGlobal, window is not defined either

So it looks like indeed the template is rendered serverside - what is the best way to move it so that it renders clientside? The header template is included in the index.ejs file like so:

<% include ./partials/header %>

<main>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
    <div name="main-div" id="main-div-id">
    </div>
</main>

<% include ./partials/footer %>

Upvotes: 0

Views: 842

Answers (2)

Andrew Burgess
Andrew Burgess

Reputation: 1797

  1. I believe the reason why appGlobal is not defined in the template is because the template is rendered server-side and not client-side; and appGlobal is a clientside global.

That's exactly right; any code (HTML, CSS, JS) that you send to the browser is not parsed in any way by the server: the server sees that code as just text. Any JavaScript that will be run in the browser hasn't been run yet when the server-side templates are being compiled.

  1. However, this code should still check to see if appGlobal is defined, so I don't see why it's throwing an error???

Well, it is, but appGlobal isn't defined on the server, because the code isn't run on the server. It's only run on the client.

  1. if I change the template to use window.appGlobal, window is not defined either

It's not defined for the same reason.

One possible solution for this is to have the appGlobal variable on the server, and then use EJS to add it to the client-side code. For example, somewhere in your server code, you probably have something like this:

ejs.render(templateStr, { data: 'here' });

(If you're using a library like Express this might look a bit different.)

If you create appGlobal on the server, you can add it as a parameter to the data object, and use it within your template as you want to in your question:

var appGlobal = {
    authorized: null,
    currentUser: null,
    env: null
};
ejs.render(templateStr, { appGlobal: appGlobal });

But then, if you want to make this variable available on the client side, you can stringify it and add it to the template. So the JavaScript would look something like this:

ejs.render(templateStr, { 
    appGlobal: appGlobal,
    appGlobalStr: JSON.stringify(appGlobal)
});

And then in your template, you can do something like this:

<script>
    var appGlobal = <%- appGlobalStr %>;
</script>

Note the use of the <%- %> delimiters, for unescaped output.

It's important to realize that this means the client will initially get the current value of the server's appGlobal variable, but they are not kept "in sync" at all. Also, make sure you are okay with the client having access to all the properties of the appGlobal object. For example, if you were doing something like this with a user record, you'd definitely not want to send the passwordHash (and many other properties, probably) to the client.

Upvotes: 1

Halim Qarroum
Halim Qarroum

Reputation: 14103

The template system you are using (EJS) is executed server-side and has no knowledge whatsoever of the semantic associated with client-side code.

In this case, the appGlobal variable declaration is never evaluated by EJS and is not accessible through the server-side scope as a consequence.

Upvotes: 3

Related Questions