MVC (if you really want it)

Yeah, we’ve heard it over and over, “I want my MVC.”We think that View First applications are easier to maintain and allow for more interactive web applications.But Lift is flexible and offers developers choice in the kind of how they want to build their apps.

Lift 2.2-M1 introduces MVCHelper, a trait that allows you to build MVC style controllers much the way Lift’s RestHelper allows you to use pattern matching to build simple REST services.A simple example that inserts the current time in an element with id “time”:


import net.liftweb.http._
import net.liftweb.util._
import Helpers._

object RootController extends MVCHelper {
  // Update the time on the index (home) page
  serve {
    case "index" :: Nil =>
    // replace the contents of the element with id "time" with the date
    "#time *" #>Helpers.formattedTimeNow
  }
}

The serve method takes a PartialFunction[List[String], MVCResponse] as a parameter.This defines a route to serve.A PartialFunction in Scala is a pattern that matches the type of the first parameter and if the pattern is matched, then the function returns the right hand side if the =>.

MVCResponse is a trait which has implicit conversions from the types you would want to return:

For Unit and CssBindFunc , the template corresponding to the URL is loaded, the CssBindFunc is applied and then the template is run through the normal Lift rendering pipeline.

A returned NodeSeq will be run through the Lift templating mechanism. For example:

serve {
  case "foo" :: _ =>
    for {
      template<-TemplateFinder.findAnyTemplate("bar" :: Nil)
    } yield ("#id" #>"frog").apply(template)
}

You can extract values from the pattern:

serve {
  case "show_param" :: param :: Nil =>
    "#param_value" #>param
}

You can use a for comprehension with a value

serve {
  case "user_name" :: user_id :: Nil =>
    for {user<- User.find(user_id)} yield "#user_name" #>user.firstName
}

You can even use Scala’s extractors to compute values from the extractor:

serve {
  case "user_name" :: User(user) :: Nil =>
    "#user_name" #> user.firstName
}

On final note you must hook your MVCHelper object up in Boot.scala:

LiftRules.dispatch.append(MyController) // Stateful
LiftRules.statelessDispatch.append(MyController) // stateless (no session)

So, if you really want your MVC, you can get it with Lift.