My Blog

How to Inject HTML into EJS Layouts on a Nodejs/Expressjs Server (and still use partials in your pages!)

My last post covered the same topic, but it had one big issue: EJS files loaded in with fs.readFile() no longer filled in the <%- include()%> with anything!

To fix this, we need to do a couple of things.

  1. Stop using fs.readFile and switch to ejs.renderFile
  2. Add asynchronous support for the router.get()'s callback function. This way we can use "await" with the file render.

I'll recap what we did in the previous blog post for those that don't want to read it again.
First, I'm routing all the traffic through the Express Router (this is in my app.js file):
Code detailing how to use routing with app.js

Next, in the /routes/index.js file, we grab a Router from Express and then we require('ejs') so we can use ejs.renderFile().
Code grabbing a router from express and adding ejs support

Here's where things change a bit from the previous blog post, we do our routing, but we make our anonymous callback function asynchronous using the "async" keyword. This let's us use the "await" keyword when we try to use ejs.renderFile(). We also added a "try-catch" to catch any errors.
Code for routing GET request and rendering the page.

And here is the about.ejs file, which contains an ejs directive to include a partial, skillsnavbar:
Code for the about.ejs page, containing an ejs inclusion of a partial

And here is the partial:
Code for the skillsnavbar partial.


The result is the same as before, but with a partial injected:
Webpage with abouTest.ejs injected into layout.ejs

And there we have it! We have fully injectable content into layouts! And that content can have content injected into it as well. Thank you for your time!



How to Inject HTML into EJS Layouts on a Node server with Express OUTDATED! See new post.

So, the layout.ejs file in views had me confused because it seemed like the only thing you could do (since EJS doesn’t support block layouts, which I assume means being able to replace blocks of content in the layout) was append a layout to the beginning or end of the html, which wasn’t ideal.

Instead, I figured I could use Node.js with Express to fill in the data for me by having it render the layout page and then just injecting my custom blocks of html into a variable on the layout.

First, I’m routing using the Express Router. Then, in the app.js, I tell the app to use this routing.
Code detailing how to use routing with app.js

Then, in the /routes/Index.js file, we require the fs (FileStream) to read a local html (or ejs) file. We also grab a Router from Express.
Code dtailing how to include router and fs filestream

Then we do our routing. Here’s an example of how it normally looks:
Code showing how to normally use router to route GET request

And here’s how I change it up:
Code showing how I change the routing to inject HTML


If you’re looking at this sideways and it still isn’t making sense, let me break it down:

  • Router.get(‘/testpage’, (req,res)=>{
    • This is how Express routes traffic when it receives a GET request from a browser for the page “/testpage”, like if you were to go to www.marcnettles.com/testpage then my server would route your GET request for “/testpage”.
    • o The (req,res)=>{ //stuff } is what is called an “Anonymous Callback function”. Callback functions are asynchronous, meaning they won’t tie up your server trying to process this request. It pulls in any information from the request with “req” and then it uses “res” to send information back, such as rendering a page for the user to see.
  • fs.readFile(“views/pages/aboutTest.ejs”, function callback_read(err,data){ //stuff }
    • This is reading in a file (an ejs file which just contains the html for an About Me article), but it is doing it asynchronously to avoid tying up the server.
  • If (err) { throw err; }
    • If the server can’t find the file, it throws an error.
  • res.render(‘layout’, { title: “Test Page | Marc Nettles”, content: data });
    • This renders the layout.ejs file in our views folder and it replaces the variable “title” with “Test Page | Marc Nettles” and “content” with “data”. “data” is the output of the fs.readFile() function we saw above. The contents of layout.ejs are given below:
    • Code for layout.ejs
    • This layout is built with EJS partials (which are just pieces of HTML in a separate file that are then loaded in here), so we don’t immediately see where the variable “title” is located, but the important part is in MAIN where we see the line “<%- content -%>
    • <%- variableName -%> is javascripts way of embedding unescaped HTML while removing whitespace. Use <%- variableName %> if you don’t want to remove whitespace.

So, we now know that the variable “content” is being replaced with the variable “data” which is filled by fs.readFile() to be the contents of the file aboutTest.ejs, which is seen below.
Code for aboutTest.ejs

Which gives us the result:
Webpage with abouTest.ejs injected into layout.ejs


And that’s it! That’s how to asynchronously inject block content into an EJS layout!