Add the Resources and Views folders

If you are reading this tutorial at a later date, and using the Vapor Web template,
then you may not need to do this (nor will you need to have manually added Leaf to your
project). But with the API template, you'll need to manually create a Resources and Views
folder. To do so, simply do the following:

Then, close your Xcode project, run vapor update and regenerate your Xcode project. Your project directory should look like this before proceeding (they must be blue folders, not yellow directories).
They should appear in your Xcode project after regenerating it.

Configuring Leaf

In order to use Leaf in our project, there are a few things we must do in configure.swift first:

Leaf syntax

Very briefly before starting, let's go over some basic syntax and theory. We learn best by examples, but it's good to know at least a little theory before diving in :D

To access variables in a leaf file, use #(variableNameHere)

Variables accessed in leaf must have been set from the controller

For loop syntax is: #for(post in posts) { The post title is #(post.title) }

To get the number of items in an array, use the count tag: #count(posts)

Other useful tags include #capitalize(name)#uppercase(name)#lowercase(name)

Syntax Coloring

If you are using Xcode, the syntax coloring can be an issue. To change the syntax coloring for a leaf file, select the file, and then
go to Editor -> Syntax Coloring -> HTML. Unfortunately, Xcode seems to forget my preferences after every Xcode restart,
so you'll need to get used to doing this for the time being :/

At this point, run your server and navigate to http://localhost:8080/allTodos, and you should see the "Hello World" text. Your first leaf view! Exciting!

Embedding

Ideally, we would like to embed our allTodos file inside our base.leaf file. This way, we could have a navigation bar, meta tags, or some other setup that is consistent across
all pages. This is quite simple. First, change the content of your allTodos.leaf to be the following:

#set("content") {
Hello World
}
#embed("base")

Then, in the body tag of your base.leaf, add:

#get(content)

Here, we embed the base HTML file in our allTodos.leaf. Then, wherever we place our #get(content) in base.leaf, our content that we set is inserted there.
In this case, it is inserted in the body of the HTML.

Displaying Todo titles inside our Leaf file

Of course, the most obvious use case for a templating engine is displaying some data from our application to the user.

In order to do this, we'll need to do a few things:

Create a struct representing the data we wish to pass to the view

Change our allTodos route to use this struct to pass the data to the view

Change our allTodos.leaf file to use the proper syntax to print them out

Create some sample Todo items using a Rest client, such as Postman

So, let's create the struct. We expect to pass back an array of Todos to the template, so create the following struct:

Finally, restart your server, and then create some sample Todos using a rest client. Once you have created a few, navigate
to http://localhost:8080/allTodos.

You should see your Todos printed out on the screen. Isn't it so satisfying?

Partials

Sometimes we have a view that we want to reuse and just insert into many different places. Maybe it's a generic blog post view, a navigation bar, footer, header, etc.
So, to keep our code DRY, we can use partials to keep these blocks of reusable code for us, and then embed them in our other views where needed.

To demonstrate how to do this in Leaf, create a new file, todo.leaf. Then, add the following content to it:

It works like this: Any variable that you have defined in your original struct, or leaf file (such as ourTodos and todo), is then available in your partial under the same variable name.

Build, run, create a few todos, and then navigate to /allTodos, and you'll see it's using your new reusable view.

Further Uses

We can also use the #set() and #embed() tags for organizing stylesheets. For example, you may have some page-specific styles you'd
like to define for only one page. In such a case, in your specific file you could do: