Up: Chapter 4

4.3 Stateful Snippets

In order for us to give the user a better experience, we need to capture the state of the name and age variables across the multiple form submissions. The mechanism that Lift has for doing this is the Stateful Snippet [D]  [D] There are no stateless snippets. A Stateful Snippet doesn’t consume any more server-side resources than does a form composed via SHtml.onSubmit(). Oh, and state is not a barier to scalaing. See .. A snippet that subclasses StatefulSnippet has an extra hidden parameter automatically inserted into the form which ensures that during processing of that form, the same instance of the StatefulSnippet will be used [E]  [E] Earlier I talked about the security implications of hidden form parameters. The hidden parameter mechanism is not vulnerable to the same issues because the hidden parameter itself is just a GUID that causes a function to be invoked on the server. No state is exposed to the client, so there’s nothing for a hacker to capture or mutate that would allow for the exploitation of a vulnerability..
Let’s look at the HTML template:
stateful.html
<div id="main" class="lift:surround?with=default&at=content">
  <div>
    Using stateful snippets for a better
    user experience
  </div>
      
  <div>
    <div class="lift:Stateful?form=post">
      Name: <input name="name"><br>
      Age: <input name="age" value="0"><br>
      <input type="submit" value="Submit">
    </div>
  </div>
</div>
​
The template looks pretty much like the template in onsubmit.html. Let’s look at the snippet itself:
Stateful.scala
package code
package snippet
​
import net.liftweb._
import http._
import common._
import util.Helpers._
import scala.xml.NodeSeq
​
/**
 * A stateful snippet. The state associated with this
 * snippet is in instance variables 
 */
class Stateful extends StatefulSnippet {
  // state unique to this instance of the stateful snippet
  private var name = ""
  private var age = "0"
​
  // capture from whence the user came so we
  // can send them back
  private val whence = S.referer openOr "/"
​
  // StatefulSnippet requires an explicit dispatch
  // to the method.
  def dispatch = {case "render" => render}
​
  // associate behavior with each HTML element
  def render = 
    "name=name" #> SHtml.text(name, name = _, "id" -> "the_name") &
    "name=age" #> SHtml.text(age, age = _) &
    "type=submit" #> SHtml.onSubmitUnit(process)
​
  // process the form
  private def process() =
    asInt(age) match {
      case Full(a) if a < 13 => S.error("Too young!")
      case Full(a) => {
        S.notice("Name: "+name)
        S.notice("Age: "+a)
        S.redirectTo(whence)
      }
      
      case _ => S.error("Age doesn't parse as a number")
    }
}
There’s a fair amount different here. First, the class definition: class Stateful extends StatefulSnippet. Because the snippet instance itself contains state, it can’t be an object singleton. It must be declared as a class so there are multiple instances.
We capture state (name, age and from whence the user came), in instance variables.
StatefulSnippets require a dispatch method which does method dispatching explicitly rather than “by-convention.”
The render method uses familiar CSS Selector Transforms to associate markup with behavior. However, rather than using SHtml.onSubmit, we’re using SHtml.text to explicitly generate an HTML <input> element with both the name and value attributes set. In the case of the first input, we’re also explicitly setting the id attribute. We’re not using it in the application, but it’s a way to demonstrate how to add extra attributes.
Finally, the process() method attempts to covert the age String into an Int. If it’s an Int, but less than 13, we present an error. If the String cannot be parsed to an Int, we present an error, otherwise we do notify the user and go back to the page the user came from.
Note in this example, we preserve the form values, so if you type something wrong in the name or age fields, what you typed is presented to you again.
The big difference between the resulting HTML for StatefulSnippets and other snippets is the insertion of <input name="F1071441222401LO3" type="hidden" value="true"> in the form. This hidden field associates the snippet named “Stateful” with the instance of Stateful that was used to initially generate the form.
Let’s look at an alternative mechanism for creating a nice user experience.
Up: Chapter 4

(C) 2012 David Pollak