Happy 4th Birthday Lift

Happy 4th Birthday Lift!

Four years ago, we started the Lift project.  Back then I was a Scala newbie, yet I had a vision that developing secure web apps should be simple, that developing interactive web apps should be simple, and that the compiler is your friend.

Four years later and 2 major releases and many milestone releases later, Lift holds true to the original vision.

Four years later, the Lift community is more than 2,500 people strong, there are hundreds of Lift apps in production and some pretty high profile sites are successfully using Lift.

For me, personally, I'm really glad that the Lift community is so awesome... full of people who are willing to help others and give the kind of feedback that helps Lift grow and expand.  I'm also really impressed by the Lift committers... nearly 50 people scattered across the world who contribute time, code, and personal attention to Lift and the Lift community.

So, on Lift's fourth birthday, I want to say thanks to the Lift community and the Lift committers for building something tremendous: Lift.

SHtml.idMemoize -- Simple Ajax Updating

Lift 2.3 has a new feature: SHtml.idMemoize.  Basically, it lets you use Lift CSS Selector Transforms yet capture the template that was run through the transform such that the you can re-render the HTML in a given Element without having to explicitly load the template that was used to render the page.

Let's take a look at an example, let's say you have some HTML:

      <div class="lift:ShowMemoize">
        <button name="refresh_all">Refresh All</button>

        <div name="one">
          <span>The current time is: </span>
          <button>Click Me</button>
        </div>

        <div name="two">       
          <button>Update this</button>
          <ul>
            <li>Count: </li>
          </ul>
        </div>
      </div>

Basically, a <div> that contains two sub-<div>s.  We want to be able to click on the buttons and have either or both of the <div>s updated (depending on which button we press).  Let's look at the Lift snippet that allows you to redraw part or all of the above HTML:

object ShowMemoize {
  def render =
    "div" #> SHtml.idMemoize(
      outer =>
      // redraw the whole div when this button is pressed
      "@refresh_all [onclick]" #> SHtml.ajaxInvoke(outer.setHtml _) &

      // deal with the "one" div
      "@one" #> SHtml.idMemoize(
        one =>
          "span *+" #> now.toString & // display the time
        "button [onclick]" #> SHtml.ajaxInvoke(one.setHtml _)) & // redraw

      // deal with the "two" div
      "@two" #> SHtml.idMemoize(
        two => // the "two" div
          // display a bunch of items
          "ul *" #> (0 to randomInt(6)).map(i => "li *+" #> i) &
        // update the "two" div on button press
        "button [onclick]" #> SHtml.ajaxInvoke(two.setHtml _)))
}

This code does the following:

  • Selects the outer <div>
  • SHtml.idMemoize is a method that takes IdMemoizeTransform => NodeSeqFuncOrSeqNodeSeqFunc as a parameter.  That type signature may look weird, so let's break it down:
    • It's a function that takes an IdMemoizeTransform as an input and
    • returns a NodeSeqFuncOrSeqNodeSeqFunc.  "What's a NodeSeqFuncOrSeqNodeSeqFunc?" you ask.  It's a NodeSeq => NodeSeq or a Seq[NodeSeq => NodeSeq]... it's basically what you get with a CSS Selector Transform... and there's an implicit conversion from either NodeSeq => NodeSeq or Seq[NodeSeq => NodeSeq] to NodeSeqFuncOrSeqNodeSeqFunc.
    • Basically, it's a function that takes the IdMemoizeTransform and returns a CSS Selector Transform
  • We capture the outer variable which is the IdMemoizeTransform and the do our normal CSS Selector Transform with it
  • We set the onclick attribute of the <button> with id refresh_all to an Ajax invocation of the outer.setHtml() method.  So, when the button is clicked, the body of the outer <div> will be redrawn based on the CSS Selector Transform and the template that was used in the transform.
  • Each of the inner <div>s get the same treatment and each has a <button> that will redraw just that part of the screen
So, the snippet does not have to explicitly know the template passed in... it will do the right thing no matter the template.  You can even have two invocations of the same snippet on the same page with different templates and SHtml.idMemoize will "do the right thing" with the templates.  This makes it easy to build Ajax applications that update the screen real estate the right way.

You can see an example at https://github.com/dpp/starting_point/tree/idMemoize

Announcing Lift 2.3-M1

The Lift team is pleased to announce Lift 2.3-M1.

Lift is an elegant, expressive framework that allows any size team build and maintain secure, highly interactive, scalable web applications quickly and efficiently. Lift is built on Scala and compiles to JVM byte-code. Lift applications deploy as web archives (WAR files) on popular application servers and web containers including Jetty, Glassfish and Tomcat. Lift applications can be monitored and managed with the same proven infrastructure used to manage and monitor any Java web application. Lift is open source licensed under an Apache 2.0 license.

This is the first milestone for 2.3 series and suports Scala 2.8.0 and 2.8.1. See the ticket tracker for full list of new features, enhancements and bug fixes.

Thank you, have fun!
- The Lift team