Play! Framework 2 is a web framework, and so is meant to create web applications. A web application is an application that presents an interactive interface through a web browser. But the browser might not be the only client of such an application, because data created while using it could be used by other applications (that's web integration). And so, very often, the server side of a web application is also exposing data through web services. Which leads us to the need, as developers, to not only generate HTML pages, but also TXT pages, XML pages, and so on.
Play! 2 provides a powerful way to create all such external representations of server-side data: a type-safe templating system based on Scala.
In this chapter, we'll cover the following topics:
This first section will concentrate on what a template is, its structure, and its features. We'll see how it can help us to easily create views in a composable and sharable fashion.
A template in Play! Framework 2 is basically a file with a specific extension that commonly resides under the views
package. So, a template filename always has the following pattern:
<template-name>.scala.<content-type>
It is composed of the following:
listContainer
). This will be used to reference it in the controllers..scala
, which is always the same. As stated earlier, templates are Scala-based..html
, .xml
, and .txt
, but Play! 2 is extensible enough to enable us to add new ones.Play! 2 will detect these files based on the pattern and will compile them into functions that will be available for the controllers or other templates.
So let's create a new template named listContainer
that renders HTML content.
A template is expected to respect a certain structure that starts with the parameters list . As a template will be compiled into a function, it can accept parameters just as any other function in Scala.
When declaring a Scala function, we need to first give it a name—the filename is the function name—and only then can we declare its parameters. So, logically, this is the first line of all templates.
These parameters are declared in exactly the same way as for Scala functions—that is, between parentheses and paired by the name and type separated with a colon—as shown in the following screenshot:
The only thing that differs is that we need to use the magic character (@
), because it's Scala code in a template. To illustrate this, we'll add two parameters to our listContainer
template.
It's pretty easy. We've just defined our template as a function that takes the following two parameters:
level
: It is of type Int
items
: A sequence containing stringsAt this stage, the Play! 2 compiler will make available to us a function with the following signature:
def function(level:Int, items:Seq[String]):Html
Play! 2 has worked out that the file is an HTML template, from the second extension (.html
) of the template name—that is, the Html
result type of the function.
Now that we have created a template with its parameters, we will define a function that produces HTML, but an empty one!
The content of a template is inserted into the file directly after the parameters' declaration.
In our case, we're about to create an HTML structure using HTML notation (the same happens for JSON, XML, and so on). So let's create some content in there:
Now, the listContainer
function will produce a small HTML instance of this simple excerpt.
Wait! It's not really useful, because it does nothing with our parameters. That's where Chapter 2, Scala – Taking the First Step, comes to our rescue. We'll use Scala to create some relevant content based on the server-side data.
As you can see, we adapted the template to use the level
parameter—which is of the type Int
—to change the flow for both the title and the list of rendered items. We used it to change the header level (h1
, h2
, and so on) and to adapt the style
attribute.
Then we used the map
function on Seq
to produce a new sequence of HTML blocks, each of them being the representation of an item.
In order to see our listContainer
template in action, we could define an action and a route that asks to render it; but what we'll do instead is call this template in our index.scala.html
template. That's how layout is achieved in Play! 2. See the following screenshot:
The previous screenshot shows how to call a template from within another one, which is basically calling a function from within another function.
The screenshot also shows the action that must render the index page; it has been covered in Chapter 1, Getting Started with Play! Framework 2.
So the index.scala.html
template/function is first declaring a single parameter message, followed by its body/definition that starts by using the main
function with two parameter blocks.
In this case, we defined an HTML block that refers another template, listContainer
, just as any other function. That's how templates are combined in Play! 2.
So far so good? Well, not exactly. Looking closely at the listContainer
call in the index.scala.html
template, we'll see that it still needs some parameters.
Let's see how to fill them.
Having composed our templates (index.scala.html
using listContainer
), we need to do two more things:
index.scala.html
using curried parameters (two sets of one parameter in this case)index
action in the Application
controller to match the new needsFirst we will modify the template to allow access to data usable by listContainer
:
For that, we added a new parameter block that adds the required data. A new parameter block is not mandatory; it's just a good way to have a clear distinction of what is needed by what. Then the data is simply re-used within the listContainer
call.
If we try to hit the index.scala.html
page right now, we'll see the same error screen as the following screenshot:
This happens when we use our Java project and we notice that the template compilation failed because parameters are missing in the template call from within the Application.java#index
action.
So, let's go to this action to pass it an integer value and a collection of strings:
Now let's check again in the browser:
Ouch! Interestingly, in the Scala template we used a Scala collection to represent our data; but going back to the controller (Java in this case), we're unable to use the classic java.util.List
collection to create our server-side data.
In order to solve this problem, there are some conversion utilities available in Scala, which can be found in scala.collection.JavaConversions
. This class provides a static method that will help us in converting our Java List to a Scala Seq: asScalaBuffer
.
Normally, everything should be OK now and we should get the following screenshot: