Reputation: 100506
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>
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
Reputation: 1797
- 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.
- 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.
- 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
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