Now that we have a good understanding of how a template can help in creating views, we'll try to adapt our templates to make them interesting. The idea is to fix all the concepts seen so far in your mind.
In the first section, we created a listContainer
template that was able to render a sequence of strings into a ul
HTML element. In this section, we'll adapt it a bit to enable a header and a footer around the list. For that, we'll use currying and the internal HTML representation of Play! 2.
So, all we have to do is redefine the listContainer
function to take two new parameter blocks, header
and footer
, which are HTML excerpts.
As expected, the type of these new parameters is Html
, which is the internal representation of HTML blocks in Play! 2. Then, we use them right before and right after the block disPlay!ing the list, and we remove the previoush1
element (which was saying Here we go!).
OK, now we must change the calling instruction in the index.scala.html
template by adding the header and footer HTML, shown as follows:
That simple! We just created the "classic" header-body-footer layout, where the former and the latter are simply passed as parameters. Having a look at their type, Html
, and how we passed them, we can see that we just wrote an HTML block (including the Scala one) at will.
The following screenshot shows the result in the browser:
Up until now, we played with integers and character strings; that was really cool, but not so representative of what we will face in the real world. Most of the time we're dealing with domain model instances that may represent complex object trees and myriad properties.
In this section, we will create an Item
class that will be used in place of String
in the list of things to be disPlay!ed. The following screenshot shows this (in both Scala and Java):
As you can see from the previous screenshot, we created the class in the models
package; this is because we've just introduced the last component of our MVC
pattern (the M part). As a
Controller is defined in the controllers
package and a View
in the views
package, a Model
commonly resides in the models
package.
To use it, we must perform the following steps:
list
parameter in the listContainer
and index
templates to use the new Item
class rather than String
.index
action to create items and not strings.What would have to be done is to modify the rendering of the list to use the data of Item
. However, we'll take this opportunity to create a dedicated template: listItem.scala.html
.
This template is meant to render an item within a list (ul
), which could be achieved in the following way:
Now that we've seen a lot of templates, listItem.scala.html
should look familiar. The only thing that is very new is the @import
statement, which should be self-explanatory.
Let's use it in the listContainer
template:
We simply adapted the list by renaming it items
, changing its type from Seq[String]
to Seq[Item]
, and finally calling the listItem
template in the map
body.
The last thing that is needed is to modify the action to create an Item
sequence. The following screenshot shows the Scala version (the Java one is left as an exercise):
Having done all of the adaptation, we can return to our browser and check what's going on.
Cool, huh? But we could do better, couldn't we?
In this section, we'll enjoy ourselves a bit by playing with what we have seen and learned so far, in order to make our application look more interesting.
The following screenshot shows what the goal is:
At this stage, we're able to show a list of items with a header and a footer, which together would define a new structure: Chat
. A chat
is a discussion between people and can occur several times in a single day. So, the following screenshot shows the definition of this class:
Quite simple and obvious. But now we're going to try to use it as the top-level type of our application; thus the index
page should render Chat
instances rather than Item
.
For that, we'll have to change the signature of the index
template to only take a list of Chat
instances (note that we'll use java.util.List
for convenience in the Java
controller). Then we'll have to adapt the listContainer
template to take a single Chat
instance; so we will have totally removed the level
parameter from the scope.
The previous screenshot shows a very simple code example that creates a bunch of Chat
instances with underlying items.
For such use cases, that is, initializing with test data, Play! has a special feature that enables a much higher level of control over the application. This feature is called a global object. Such an object is a singleton that will be created by Play! at startup and will provide plenty of hooks such as onStart
and onBadRequest
. This object in Scala or class in Java should be created keeping in mind the following points:
GlobalSettings
type (provide default implementations for all hooks)Global
, or its fully qualified path must be configured in the application.conf
file using the key application.global
With this object created, one could override onStart
in such a way that data can be created for testing purposes.
The problem now is that the Chat
instances are completely shuffled, and if we leave the listContainer
template as is, we'll get something similar to the following screenshot:
Which is ugly!
To solve this, we'll use Scala at full power by using the following methods: sortBy
and groupBy
on Seq
, and toSeq
on Map
. The following screenshot shows our new "empowered" template:
As we can see from the previous screenshot, we're able to use the methods we saw in Chapter 2, Scala – Taking the First Step, on java.util.List
. That's because of some magic that implicitly converts List
instances to Seq
on the fly. But we won't cover this in the book.
Calling this template, we get a not found: dataAndChats
error. This is because of the formatting used to align the methods chaining after @chats
. This is a sad limitation of the template compiler, it needs Scala stuff to be single lined if not wrapped in curly braces.
In short, the following steps explain what has been done on the chats
list:
Map
instance where the date is the key and the list of chats is the value.Checking back in the browser, we'll get the result disPlay!ed at the start of this section.
Funny, huh? Now, try to make exactly the same kind of sorting and grouping using Java; (just joking).