Eta Syntax and JavaScript
Learning objectives
- You know how template values are used in Eta.
- You know how to use JavaScript in Eta.
- You know where to look for Eta errors.
Let us dive deeper into Eta syntax. Eta syntax can be divided into two parts, where one part is related to replacing template values with data from the server, and the other is related to JavaScript operations in files.
Template values
Previously, we briefly looked into using template values in our Eta documents. Template values are used in view templates for indicating positions into which data from the server is added. We already took a peek at this when adding data to a document.
There are two ways of inserting data, which are as follows:
The format that starts with
<%=
, followed by a variable name with anit
-prefix, and a%>
, is used for inserting variable values to the document. In this format, possible HTML content in the variable is escaped, which means that HTML content from a variable is modified so that the content is not shown as HTML, but as text. In practice, this means that e.g. smaller than signs<
are represented with equivalent HTML entity tags, in this case<
. All variables passed to Eta from the server in have a prefixit
in Eta view templates, meaning that a variable calledname
from the server is added to an Eta document as<%= it.name %>
.The format that starts with
<%~
, followed by a variable name with anit
-prefix, and a%>
, is also used for inserting variable values to the document. In this format, however, possible HTML content in the variable is not escaped, which means that HTML content is shown as HTML. Similarly, to the previous, all variables from the server have a prefixit
, meaning that a variable calledname
from the server is added to an Eta document as<%~ it.name %>
.
Let's look at the difference of these two in practice. The following Eta document uses both formats for showing a variable. The %lt;
and >
are character entity references for the <
and >
signs. Modify the index.eta
file in the templates
folder to match the following (i.e., add the two lines for adding an escaped HTML entry and a non-escaped HTML entry).
<!DOCTYPE html>
<html>
<head>
<title>Hello there!</title>
</head>
<body>
<h1>The heading: <%= it.heading %>!</h1>
<p>The secret: <%= it.secret %>!</p>
<p>The count: <%= it.count %>!</p>
<p>Escaped HTML: <%= it.variable %>!</p>
<p>Non-escaped HTML: <%~ it.variable %>!</p>
</body>
</html>
And modify the app.js
to match the following. The variable
that contains an HTML element is added to the data
object.
import { Eta } from "https://deno.land/x/eta@v3.4.0/src/index.ts";
import { Hono } from "https://deno.land/x/hono@v3.12.11/mod.ts";
const eta = new Eta({ views: `${Deno.cwd()}/templates/` });
const app = new Hono();
const data = {
count: 0,
secret: "Illuminati",
heading: "Hello world!",
variable: "<strong>Epic HTML!</strong>",
};
app.get("/", (c) => {
data.count++;
return c.html(eta.render("index.eta", data));
});
Deno.serve(app.fetch);
When you run the server and make a request to it, we see the following response.
curl localhost:8000
<!DOCTYPE html>
<html>
<head>
<title>Hello there!</title>
</head>
<body>
<h1>The heading: Hello world!!</h1>
<p>The secret: Illuminati!</p>
<p>The count: 1!</p>
<p>Escaped HTML: <strong>Epic HTML!</strong>!</p>
<p>Non-escaped HTML: <strong>Epic HTML!</strong>!</p>
</body>
</html>%
What we observe is that the HTML content following "Escaped HTML: " has been escaped, while the HTML content following "Non-escaped HTML: " has not been escaped. When you try opening the page in the browser, you notice a difference in how the texts are shown.
We will look into why escaping content from the server is important when discussing security concerns in web applications.
JavaScript in view templates
JavaScript can be added within a view template using the format <% code %>
, where code
stands for code to be added. This allows us to use JavaScript to create dynamic content in view templates. The use of JavaScript in view templates is outlined in the following example, where the secret is added to the HTML document only if the value of count is 1.
<!DOCTYPE html>
<html>
<head>
<title>Hello there!</title>
</head>
<body>
<h1>The heading: <%= it.heading %>!</h1>
<% if (it.count === 1) { %> <p>The secret: <%= it.secret %>!</p> <% } %> <p>The count: <%= it.count %>!</p>
<p>Escaped HTML: <%= it.variable %>!</p>
<p>Non-escaped HTML: <%~ it.variable %>!</p>
</body>
</html>
When we run the application (restarting it at first to reset the count), we see the following output when making requests to the server.
curl localhost:8000
<!DOCTYPE html>
<html>
<head>
<title>Hello there!</title>
</head>
<body>
<h1>The heading: Hello world!!</h1>
<p>The secret: Illuminati!</p>
<p>The count: 1!</p>
<p>Escaped HTML: <marquee direction='up'>Epic HTML!</marquee>!</p>
<p>Non-escaped HTML: <marquee direction='up'>Epic HTML!</marquee>!</p>
</body>
</html>%
curl localhost:8000
<!DOCTYPE html>
<html>
<head>
<title>Hello there!</title>
</head>
<body>
<h1>The heading: Hello world!!</h1>
<p>The count: 2!</p>
<p>Escaped HTML: <strong>Epic HTML!</strong>!</p>
<p>Non-escaped HTML: <strong>Epic HTML!</strong>!</p>
</body>
As we can see from above, the <p>The secret: Illuminati!</p>
is only included in the response when the count is 1. When the count is 2, the secret is not included in the response. This is because the if
-statement checks for the value of the variable count
and only includes the secret if the value is 1.
Let's look at the part with the if
-statement in a bit more detail.
<% if (it.count === 1) { %> <p>The secret: <%= it.secret %>!</p>
<% } %>
At the beginning of the first line, the <%
-sign starts Eta JavaScript syntax (smaller than symbol, percentage symbol, and a whitespace). This is followed by an if
-statement, which checks whether the value a variable called it.count
is 1
-- the it
is a prefix that notes that the variable comes from the server. The if
statement is opened with the curly bracket -- everything until the next closing curly bracket belongs within that if
statement. After the curly bracket, the Eta JavaScript syntax is closed with a %>
-sign (a whitespace, percentage symbol, and a greater than symbol).
The following line contains both HTML and a Eta template value.
<% if (it.count === 1) { %>
<p>The secret: <%= it.secret %>!</p><% } %>
The Eta template value <%= it.secret %>
is replaced with the value of the variable secret
-- in this case, when looking at the code on the server, Illuminati
. This, when combined with the HTML, creates the message that is shown as a response to the request, i.e. The secret: Illuminati!
.
On the last line, we close the if
-statement. The ending curly bracket matches the starting curly bracket, closing the block that contains the HTML heading and the template value.
<% if (it.count === 1) { %>
<p>The secret: <%= it.secret %>!</p>
<% } %>
Similar to adding an if
-statement, we could also have an if-else
statement in the code. The following example highlights how the program could be modified to include a message when the count is not 1.
<% if (it.count === 1) { %>
<p>The secret: <%= it.secret %>!</p>
<% } else { %>
<p>Move along, nothing to see here!</p>
<% } %>
Eta and syntax errors
Note that like any syntax, Eta is susceptible to syntax errors. If we, for example, leave out the last curly bracket, we receive a response stating Internal Server Error
.
<% if (it.count === 1) { %>
<p>The secret: <%= it.secret %>!</p>
<% %>
curl localhost:8000
Internal Server Error%
When we look at the server logs, we see an error highlighting that something is wrong with the template.
deno run --allow-net --allow-read --watch app.js
Trace: Eta Error: Bad template syntax
Unexpected token ')'
====================
// ... further details details
In the above example, the error indicates that the template syntax was erronous. From this, we can suspect that the fault lies in the Eta file, which we would look into for possible issues.