I get UIkit is not defined
though the JS is loaded in the header. Even alert
doesn't work. How to solve this?
EJS index template-
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/uikit.min.css" />
<script src="js/uikit.min.js"></script>
<script src="js/uikit-icons.min.js"></script>
<title>Site</title>
</head>
<body>
<% if (message) {%>
<%= UIkit.notification(message) %>
<% }; %>
</body>
</html>
Express app JS
var message = 'Error - not found';
//routes
app.get('/', (request, response) => {
response.render('index', {message: message});
}
Error
17| <% if (message) {%>
>> 18| <%= UIkit.notification(message) %>
19| <% }; %>
20| <div >
UIkit is not defined
Error on trying alert
17| <% if (message) {%>
>> 18| <%= alert('test') %>
19| <% }; %>
20| <div >
alert is not defined
CodePudding user response:
There seems to be some confusion about which code runs on the server and which code runs on the client.
In your setup, EJS is running on the Node server and building a string of HTML that's eventually sent to the client where it's executed in the client's browser. The EJS <%= ... >
syntax lets you evaluate a JS expression in Node context on the server, not in the browser, letting you inject dynamic content into the HTML string.
Here, <%= alert() =>
says "call Node's alert
function on the server and inject the return value into the template". But that makes no sense--Node has no such alert()
function, nor does it have access to anything that might have been included in a <script>
. All of that stuff won't be available until long after EJS has finished building the HTML string and sent it to the client.
Probably what you're trying to do is inject the string that represents the function you want to call into the template:
eval(ejs.render(`<%= "alert(42)" %>`));
<script src="https://unpkg.com/[email protected]/ejs.min.js"></script>
Rather than the failing code:
window.alert = undefined; // simulate Node, which has no alert()
console.log(ejs.render(`<%= alert(42) %>`)); // fail, trying to call undef func
<script src="https://unpkg.com/[email protected]/ejs.min.js"></script>
In the top example, the string "alert(42)"
is injected into the template and sent to the "client", where eval()
invokes it, roughly simulating how your script will ultimately be evaluated.
At any rate, there's probably a better way to achieve this result of conditionally setting up a function call, but getting clear on the concept is 99% of the battle.
For example, syntax like this is possible as well:
const template = `
<% if (message) {%>
alert("<%= message %>")
<% }; %>
`;
eval(ejs.render(template, {message: "hey"}));
<script src="https://unpkg.com/[email protected]/ejs.min.js"></script>
Pop quiz: if you replace alert("<%= message %>")
with alert(message)
in the above code, will it work? Why or why not? Try it and see.
If you can answer this question, you probably understand the difference between evaluating something while EJS runs versus evaluating EJS' output.
Note: eval
is used purely for convenience/pedagogical purposes only here to simulate the client evaluating the HTML script; I'm not advocating using it in a real app!
CodePudding user response:
I am assuming you have already installed EJS with npm install ejs
.
Make sure you have the following middleware in your express app (I always missed this middleware as a beginner):
app.set("view engine", "ejs");
As far as alert() is concerned, as others have pointed out, alert() won't work as you run it on the server. EJS gets converted to HTML via its engine before it is rendered on the client side.