This article is based on Lift in Action, to be published on July 2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) ebooks and pbooks. MEAPs are sold exclusively through Manning.com. All print book purchases include an ebook free of charge. When mobile formats become available all customers will be contacted and upgraded.
also read:
Using JSON forms with AJAX
Introduction
Lift has several different ways of interacting with forms and AJAX, and you can quite easily configure Lift to create an AJAX form using SHtml. SHtml contains many useful methods and should be your main port of call for all of the out-of-the-box AJAX functionality. One of the other interesting facilities that this object provides is the ability to create forms that are serialized and sent to the server using JSON. Listing 1 details an example of using a JSON form.
Listing 1 Implementing JSON Form
import scala.xml.NodeSeq import net.liftweb.util.JsonCmd import net.liftweb.util.Helpers._ import net.liftweb.http.{SHtml,JsonHandler} import net.liftweb.http.js.{JsCmd} import net.liftweb.http.js.JsCmds.{SetHtml,Script} class JsonForm { def head = Script(json.jsCmd) #1 def show = { "#form" #>((ns: NodeSeq) => SHtml.jsonForm(json, ns)) #2 } object json extends JsonHandler { #3 def apply(in: Any): JsCmd = SetHtml("json_result", in match { case JsonCmd("processForm", _, params: Map[String, Any], _) => #4 <p>Publisher: {params("publisher")}, #4 Title: {params("title")}</p> #4 case x => <span class="error">Unknown issue handling JSON: {x}</span> }) } } #1 Registers JSON serialize function #2 JSON form wrapper #3 Custom JSON handler #4 Parameter handling
Here, you can see that this is a basic class with a few snippet methods. #1 details a snippet that simply adds a JavaScript element to the page. Typically, you would call this method from the <head> tag within your template so that the head is merged into the main page template. The point of this is that the JsonHandler implementation— in this instance the JSON object—contains JavaScript that registers a function to serialize the passed object to JSON. #2 is a snippet method setup that simply binds to the jsonForm method passing the JsonHandler instance and the passed NodeSeq. This generates a <form> element that will wrap the fields in your template. A point of note here is that the fields in your template won’t have randomized names because they are not generated with SHtml helpers. They are “raw” from the template so, from a security perspective, this is important to keep in mind.
Listing 2 shows the full contents of the template. Section #3 is the implementation of the JsonHanlder, but specifically the point of interest is #4. This defines the handling of parameters passed from the browser. As params is a Map, you must be careful to request only the keys that actually exist because this could throw a runtime exception if the key you are expecting does not exist.
Listing 2 Template implementation for JSON form
<div class="lift:surround?with=default;at=content"> <head> <script type="text/javascript" src="/classpath/jlift.js" /> #1 <lift:json_form.head /> #1 </head> <h2>JSON Form</h2> <div id="form" class="lift:JsonForm.show"> #2 <p>Book Name: <br /><input type="text" name="title" /></p> #3 <p>Publisher: <br /> <select name="publisher"> #3 <option value="manning">Manning>/option> #3 <option value="penguin">Penguin</option> #3 <option value="bbc">BBC</option> #3 </select> #3 </p> <p><input type="submit" /></p> #3 </div> <hr /> <h2>JSON Result</h2> <div id="json_result">>/div> #4 </div> #1 Includes jlift.js #2 Calls snippet method #3 Input fields #4 Result element
Lift actually provides a specialized client-side JavaScript library with a set of helper functions for conducting operations such as serializing forms, handling collections, and so forth, called jlift.js. Here it is included at #1, which is important; otherwise, the AJAX functionality would not operate as expected. When the library is included and the head method in the JsonForm class is called from the template, you will be left with something similar to the following:
<script src="/classpath/jlift.js" type="text/javascript"></script> <script type="text/javascript"> //<![CDATA[ function F950163993256RNF(obj){ liftAjax.lift_ajaxHandler('F950163993256RNF='+ encodeURIComponent(JSON.stringify(obj)), null,null); } //]]> </script>
You need to call the head method from your template so the rendered output includes this function.
also read:
Summary
We covered how you can leverage the SHtml AJAX builder methods to create page elements that trigger server-side actions. The powerful thing about Lift‘s AJAX system is that you can capture the logic to be executed upon making the specific callback within a Scala function.