Let's Learn Adonis 5: Introducing The Edge Template Engine

In this lesson, we learn the basics of the Edge Templating Engine, which allows us to dynamically inject our server-side data into our HTML views.

Published
Apr 10, 21
Duration
12m 3s

Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.

Adocasts

Burlington, KY

Adonis utilizes the Edge template engine for its view rendering. It allows us to inject server-side data into our HTML. Since we selected Web Application when we created our project, Edge is already set up for us. However, it's worth noting you can also add it to a pre-existing application as noted in the Adonis documentation.

Creating Views

We can create new views in two different ways, either by manually creating the files or using the Ace CLI. By default, all of our views should reside within our /resources/views directory. So, if you're manually creating your views, create your new .edge files within that directory.

To create a new view using the Ace CLI, open your terminal and enter the following.

$ node ace make:view project

CREATE: resources/views/project.edge
Copied!

This will create a new empty view within our /resources/views directory called projects.edge.

Adonis & Edge

Edge can be treated the same as HTML. All HTML 5 syntax is valid Edge. So, there's nothing new to learn there. So, to start within our new project view, we can stub a quick HTML 5 document out with a simple heading.

<!-- resources/views/project.edge -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Projects</title>
</head>
<body>
  <h1>Projects</h1>
</body>
</html>
Copied!

If you're using VS Code, it does not support Edge templates out of the box. However, there's a really good extension by Luong Nguyen that'll add Edge support for us called "Edge template support".

Now we already have a ProjectsController and a resource defined for our project routes, so let's go tell the index method to render our new page instead of returning a JSON response.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Database from '@ioc:Adonis/Lucid/Database';
import Project from 'App/Models/Project'
import User from 'App/Models/User';

export default class ProjectsController {
  public async index ({ view }: HttpContextContract) {
    const projects = await Project.query().withCount('tasks')

    return view.render('project')
  }

  // ... other methods
}
Copied!
  • app
  • Controllers
  • Http
  • ProjectsController.ts

Now we're ready to start up our server and test it out.

$ node ace serve --watch
Copied!

Once your server boots, head into your browser and visit http://localhost:3333/projects. You should see your H1 "Projects" title.

This is the flow you'll take for all new pages you want to add to your application.

Passing Data from Controller to View

To pass data from our controller into our view all we need to do is supply that data to the second argument of the render method within our controller.

public async index ({ view }: HttpContextContract) {
  const projects = await Project.query().withCount('tasks')

  return view.render('project', { projects })
}
Copied!
  • app
  • Controllers
  • Http
  • ProjectsController.ts

Note that the second argument, our data, must be provided as an object. The key name, projects, is what the value will be under when we use the data in our view. Next, to show our data in our view we can make use of Edge's curly brace syntax, similar to VueJS, to inject the data onto our page.

<!-- resources/views/project.edge -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Projects</title>
</head>
<body>
  <h1>Projects ({{ projects.length }})</h1>
</body>
</html>
Copied!

Give it a save, jump back into your browser, and refresh and you should now see the number of projects stored in your projects table injected onto the page.

A little side note, when using double curly braces the content being injected will be escaped to help prevent XSS attacks. If you need to render out trusted raw HTML, you can do so by using three curly braces.

<div class="prose">{{{ myHTMLString }}}</div>
Copied!

Also, if you're using VueJS inside an Edge template and you want Vue to use the curly braces instead of Edge, you can instruct Edge to ignore the curly braces by prefixing them with the @ symbol.

<h1>VueJS says @{{ hello }}</h1>
Copied!

Edge Comments

Edge also has its own form of comments. Of course, you could also use HTML comments, however, the benefit of Edge comments is that they won't be included in the final HTML sent to the user so you'll save some bytes. The Edge comment syntax is two dashes inside two curly braces, like so:

<div>
	{{-- I'm a comment --}}
</div>
Copied!

Edge Conditional Statements

Edge also supports conditional statements, like if statements.

<body>
  <h1>Projects ({{ projects.length }})</h1>

  @if (projects.length)
    {{--  TODO: List projects  --}}
  @endif
</body>
Copied!

So, here if we have at least one project to display, then Edge will render out the contents between the @if and @endif statements. Note that @if must be closed with an @endif.

We can also utilize else and elseif as well.

<body>
  <h1>Projects ({{ projects.length }})</h1>

  @if (projects.length)
    {{--  TODO: List projects  --}}
  @elseif(projects.length > 100)
    Lots of projects
  @else
    <a href="#">
      Add a project to get started
    </a>
  @endif
</body>
Copied!

Or you can use @unless to perform a negative if statement

<body>
  <h1>Projects ({{ projects.length }})</h1>

  @if (projects.length)
    {{--  TODO: List projects  --}}
  @endif

  @unless(projects.length)
    <a href="#">
      Add a project to get started
    </a>
  @endunless
</body>
Copied!

Ternary statements are perfectly valid as well.

<h1>{{ projects.length ? 'Your Projects' : 'You Need A Project' }}</h1>
Copied!

Edge Loops

We can also loop through arrays and objects with Edge as well. So, to loop through each of our projects we could do something like the following.

<body>
  <h1>{{ projects.length ? 'Your Projects' : 'You Need A Project' }}</h1>

  @if (projects.length)
    @each(project in projects)
      <h3>{{ index }} - {{ project.name }}</h3>
    @endeach
  @endif

  @unless(projects.length)
    <a href="#">
      Add a project to get started
    </a>
  @endunless
</body>
Copied!

Or, if we need the loop index, we can do the following.

@each((project, index) in projects)
  <h3>{{ index }} - {{ project.name }}</h3>
@endeach
Copied!

Now, each is also compatible with else, so we could simplify our HTML a little to eliminate the need for our if and unless statements altogether.

<body>
  <h1>{{ projects.length ? 'Your Projects' : 'You Need A Project' }}</h1>

  @each(project in projects)
    <h3>{{ project.name }}</h3>
  @else
    <a href="#">
      Add a project to get started
    </a>
  @endeach
</body>
Copied!

So, here if we have at least one project, they'll be looped through and displayed. If we don't have at least one project, then our else statement with a link to add a project will be displayed.

Lastly, if we need to loop through an object we can do the following

@each((value, key) in { example: 1, another: 2 })
  <p>{{ key }}: {{ value }}
@endeach
Copied!

Next Up

So, that's a quick introduction to the Edge templating engine and how we can use it to display data coming from our Adonis controllers. In the next lesson, we'll be focusing on cleanliness. We'll learn how we can extract layouts and partials from our views. Then, in the lesson after that, we'll learn about how we can create reusable components

Join The Discussion! (0 Comments)

Please sign in or sign up for free to join in on the dicussion.

robot comment bubble

Be the first to Comment!