Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Edge templates

Returning HTML as a string from a controller is awkward. For pages AdonisJS has the Edge template engine: a template is a file with HTML and data inserts, and the controller only passes data into it. Templates live in resources/views/ and have the .edge extension.

Creating a template

node ace make:view pages/posts/index

The command creates an empty file resources/views/pages/posts/index.edge. Write in it:

{{-- resources/views/pages/posts/index.edge --}}
<h1>{{ title }}</h1>
<p>Total posts: {{ posts.length }}</p>

Double curly braces print the value of a JavaScript expression. {{-- ... --}} is an Edge comment, it does not reach the HTML.

Rendering a template from a controller

// app/controllers/posts_controller.ts
import type { HttpContext } from '@adonisjs/core/http'
 
export default class PostsController {
  async index({ view }: HttpContext) {
    const posts = [
      { id: 1, title: 'First post' },
      { id: 2, title: 'Hello, AdonisJS' },
    ]
    return view.render('pages/posts/index', { title: 'Blog', posts })
  }
}

view.render takes the template path relative to resources/views without the extension, and an object with data. The object's keys become template variables. Open /posts — you see the heading "Blog" and the line "Total posts: 2".

Conditions

{{-- resources/views/pages/posts/index.edge --}}
@if(posts.length === 0)
  <p>No posts yet.</p>
@elseif(posts.length === 1)
  <p>One post.</p>
@else
  <p>Posts: {{ posts.length }}</p>
@end

Edge tags start with @, and a block is closed with @end.

Loops

The @each tag iterates over an array. The @else branch inside it runs when the array is empty:

{{-- resources/views/pages/posts/index.edge --}}
<ul>
  @each(post in posts)
    <li>
      <a href="{{ route('posts.show', { id: post.id }) }}">{{ post.title }}</a>
    </li>
  @else
    <li>No posts yet.</li>
  @end
</ul>

The page shows a list of titles, each one a link to the post. You get the item index with @each((post, index) in posts).

Escaping

Edge escapes everything printed with {{ }}: if a post title contains <script>, it is shown as text, not executed. When HTML must be printed as is, for example post text from a trusted editor, use triple braces:

{{-- resources/views/pages/posts/show.edge --}}
<article>{{{ post.bodyHtml }}}</article>

Common mistake

Triple braces around text a user typed open the door to an XSS attack: someone else's script runs in every visitor's browser. Print user data only with {{ }}, and keep {{{ }}} for HTML you built and cleaned yourself.

Thanks for reading!

Donate to the site — we work hard for you.