View First

First person references in this article are from Lift’s creator, David Pollak

The Lift design is born from experience with a variety of technologies including Rails. The first design goal with lift was to make sure that no programming logic and no programming symbols make it into the static display templates – one of the best papers on this subject is Terrence Parr’s work on StringTemplate

ERB and JSP and ASP all have the fatal flaw of allowing code in the view; this is bad for a bunch of reasons:

So, the static templates in lift are strictly display only. They can be manipulated with standard design tools . They can never contain program logic.

Some Asides

So, the quintessential use of lift’s templates are as follows:


<html>
  ......
  <div class=lift:my_snippet.myForm&form=post">
    <tr>
      <td>Name</td>
      <td><input id="name" type="text"/></td>
    </tr>
    <tr>
      <td>Birthyear</td>
      <td>
      
          <select>
            <option>2007</option>
            <option>2006</option>
          </select>

      </td>
    </tr>
    <tr>
      <td>&nbsp;</td>
      <td><input type="submit" value="Add"/></td>
    </tr>
  </div>
  ......
</html>


So we’ve got a lift snippet invocation with the valid HTML form. This page can be viewed in a browser or opened and edited in Dreamweaver.

In Lift, the snippet is the equivalent of a Rails controller: it is the instantiation of a class and invocation of a method on the class – because you can have multiple snippets on a page, you can call out multiple logic streams on a given page and there’s no need to choose the “primary” logic stream.

The

'form=post'
attribute is a shortcut. It automatically wraps the enclosed DOM elements in:

<form method="post" target="{current page...it's a post-back}">...</form>

You can mark bind points for business logic via CSS class names, ids, or almost any other way of finding an Element. They allow your snippet to easily replace the tag and its children with what is supposed to be displayed.

So, your lift code will look like:


  class Show {
    def myForm = {
      var name = ""
      def handleYear(year: String) {
        // the form's been submitted... do something
      }

      "#name" #> SHtml.text(name, name = _) &
      "select" #> SHtml.select((1900 to 2007).toList.reverse.map(
          v => (v.toString, v.toString)),Empty, handleYear _)
    }
  }

Note that no display code has crept into the snippet; you’ve simply bound the HTML created by text() and select() to the element with an id “name” and the select element in the incoming HTML.

Also, you’ve bound two functions to the HTML form elements. When the form is POSTed, these functions will be statefully invoked.

If you are displaying a table rather than a form, then the same binding logic still works. For example:


  
<table>
  
    <tr class="lift:ShowUsers">
      <td class="first_name">David</td>
      <td class="last_name">Pollak</td>
    </tr>
</table>

And the Scala:


  
class Show {
  def users = 
    "tr *" #> ((ns: NodeSeq) => 
      Users.findAll.flatMap(user =>
        (".first_name *" #> user.firstName & ".last_name *" #> user.lastName).apply(ns)))
}

If you take the time to clearly define the bind points, then you can have no display code at all in your snippets.

Has display logic ever crept into a method called from an ERB template?
Yes, and very often it’s a source of a potential Cross Site Scripting vulnerability.

Has business logic ever crept into an ERB template?
Yes.

In Lift, display can creep into a snippet, but business logic cannot creep into a the static display template. Yes, your designers will still have to police putting display logic in the snippet code, but the coders will not have to police business logic in the templates.