(For more resources related to this topic, see here.)
Designer friendly templates (Simple)
You somehow need to weave the backend functionality into these web pages. Countless approaches exist that try to bridge the two. Lift is also unique in this regard in that it lets you create valid HTML5 or XHTML templates that contain absolutely no business functionality, yet it manages to combine the two in an inspiring and clear way.
Again, we will use the example application from the Preparing your development environment (Simple) recipe to talk about the different concepts.
You will find the templates under the webapp directory inside src/main. If you open them, you will see they're plain and simple HTML files. It's easy for designers to edit them with the tools they know.
How to do it...
Lift's page templates are valid XHTML or HTML5 documents that are parsed and treated as NodeSeq documents (XML, basically) until served to the browser.
The standard path for everything webby is src/main/webapp inside your project. Say you enter a URL liftapp.com/examples/templates and provide the user with access to this page (see the SiteMap task for details), Lift will search the templates.html page inside the examples directory located at src/main/webapp. That's the normal case. Of course you can rewrite URLs and point to something entirely different, but let's now consider the common case.
Let's look at a simple template for the example applications' home page,
<meta content="text/html; charset=UTF-8"
<h2>Welcome to your project!</h2>
Welcome to your Lift app at
<span id="time">Time goes here</span>
Granted, this page doesn't do much, but that's all there is to this page.
In most applications you have some common parts on a page and some that change content. It's easy to define these hierarchies of templates. In your page template you define by which parent template you want it to be surrounded with and at which place. The parent template itself can also be surrounded by another template, and so on. This is a useful feature to extract common parts of a page into base templates and build on top of these to finally define the structure and surrounding chrome of your pages.
The parent template for this page is called default.html and is searched for in the templates-hidden folder. Any file that is embedded into a page is searched underneath templates-hidden. We omit the CSS and some of the Boilerplate and just show the interesting parts of the parent template's content:
<div class="column span-6 colborder sidebar">
<hr class="space" >
<hr class="space" >
<hr class="space" >
<hr class="space" >
<div class="column span-17 last">
<div id="content">The main content goes here</div>
This template defines a sidebar and places our menus there. It defines a place where messages are shown that are sent from Lift with its S.notice, S.warning, and S.error methods. And finally, it defines an ID (content) that marks the element receiving the page content.
How it works...
Let's walk through the code snippet given in the preceding section and see how the pieces fit together.
In the page template we tell Lift where the template actually starts. You can create complete, valid HTML pages and then make Lift cut the central piece out for its rendering process, and your designers can still work with complete pages that they can process in isolation from the rest. This line tells Lift that the content starts with the element with the ID, main.
The next thing we do is to define a parent template that we use to surround the page with. This way, we define essential page layout markup only once and include it everywhere it's needed. Here's how you surround a page with a parent template:
<div id="main" data-lift="lift:surround?
… your content here…
In the class attribute of the div element you call the surround snippet and hand it over the with=default and at=content parameters. The surround snippet now knows that it should find a template called default.html and insert the content of this div element into the parent template at the point defined by the ID, content. Speaking of snippets, it is a mechanism to process parts of your HTML files the same way for built-in snippets as it is for your own. Snippets are pieces of logic that get weaved into the markup. We'll get to this integral part of Lift development really soon.
Lift templates are the files that are not defined in the SiteMap. They are located at a subfolder called templates-hidden. They cannot be accessed directly from the URL, but only through code by directly opening it or through the surround-and-embed mechanisms inside other templates or pages.
Have a look at the parent template default.html shown previously. This file, along with the other files we discuss here, is available in the source code that comes with the book. It's a standard HTML5 file defining some styles and finally defining a div element to bind the child content:
<div id="content">The main content will get bound here</div>
Lift will remove the text inside the DIV and replace it with the actual content, as shown in the following screenshot:
A few other things at the top of the template are worth noting:
<script id="jquery" src = "/classpath/jquery.js""
Lift comes bundled with the Blueprint CSS framework (http://blueprintcss.org/) and a version of jQuery (http://jquery.com/). It's intended to make it easier for you to start, but by no means are you bound to using Blueprint or the included jQuery version. Just use your own CSS framework (there's a recipe on using Twitter's Bootstrap) or jQuery where it makes sense.
For instance, to use a hosted version of the latest jQuery library, you would replace the script tag from the preceding code snippet with the following:
Lift provides some standard snippets which you can use to build up your pages. The default.html template utilizes a snippet to render a menu and another snippet to place messages on the page:
When you define the element that encloses the menu, Lift will automatically render it. If you omit the group parameter, all menu entries will be rendered. Having that parameter will restrict the menu only to the items within that group. You can assign a menu group (called LocGroup) in the SiteMap you defined in the Boot class.
This snippet call will render messages that are produced by the backend application in this spot.
We will now have a look at execution order.
In normal execution mode, Lift first evaluates the outer snippets and then layer by layer moves to the inner snippets. If you want to include the result of some inner snippet evaluations to the input of the outer snippets, you need to reverse that process. For that very reason, Lift provides a snippet parameter, eager_eval=true, that you add to the outer snippet:
Adding that parameter causes Lift to first evaluate the inner snippet and then add the result of the inner snippet call to the input that is processed by the outer snippet.
You can also embed templates into your page or other templates. That's the opposite operation of surrounding a page, but equally simple. In your page, use the embed snippet to embed a template:
The what parameter defines the path to the template, which is searched for within the webapp directory.
We will now see the programmatic embedding of templates.
You can easily search a template and process it programmatically. In that case you need to specify the templates-hidden directory; that way you are able to access top-level pages as well.
val ns:Box[NodeSeq] = S.runTemplate(List("templates-hidden",
"examples", "templates", "awesome"))
Please see the EmbedTemplates snippet for an example of how to programmatically access templates and apply transformations before embedding it.
As you can see, our own templates are called just the same way as Lift's default templates, and they can do the same things.
Programmatic access to templates is useful, for instance when you want to send HTML e-mails. Inside the mail sender you would grab the template, process it (see CSS Selectors), and send the complete HTML to the recipient.
There are a myriad more reasons or use cases when you want to access your templates from your Scala code. Just keep in the back of your mind that you can do it.
The S.runTemplate method will fetch the template and process it. That means it will look for any embedded Lift snippet calls and execute them. These snippet calls could potentially embed other templates recursively.
If you do not want the template to be processed, you can retrieve it like this:
val tpl:Box[NodeSeq] = Templates(List("templates-hidden", "examples",
Lift templates are very powerful, and they have to be. They are at the basis of every web application and need to handle a lot of different scenarios.
The separation between the markup and the logic keeps the templates clean and prohibits your designers from breaking code. It might take a while to adopt to this template style if you come from a framework that mixes markup and code. We believe, especially in larger applications, you will soon see the benefits of a clear separation and encapsulation of your logic in reusable pieces. Speaking of reusable pieces, let's head over to snippets, Lift's way to plug functionality into templates.
The Lift wiki offers further information about templates and binding at the following links:
In this article, we learned about designer friendly templates.
Resources for Article :
- RESTful Web Service Implementation with RESTEasy [Article]
- Spring Roo 1.1: Working with Roo-generated Web Applications [Article]
- Deploying your Applications on WebSphere Application Server 7.0 (Part 1) [Article]