Introduction
Lift is considered to be one of the most complex and at the same time powerful web-frameworks existing at the moment (albeit little known), largely because it actively uses the functionality of the Scala language. To study it you need to make a lot of effort. But it's worth it, if only because it is very different from standard MVC frameworks and knowledge of alternative technologies will broaden your horizons.
In this article I will talk about the main features of this framework.
View first
Probably the most important feature is the View First concept. This means that View (XML template) is the entry point into your application (as opposed to traditional methods, where the controller is the input point). Scala code is not embedded in View (in Lift - it is impossible to write logic on the page), but called from a template. Thanks to the View First concept, each element (form, search field, chat, list of something, etc.) can be completely isolated from others in a separate snippet. This greatly reduces the connectivity of components and makes it easy to reuse them in other parts of the site.
So, for example, a snippet will look, which is responsible for the logic of the form:
')
class Snippet = { def form_elements = { var textValue: String = "" var selectValue: String = "" def process() { println(textValue) println(selectValue) }
And the pattern:
<form lift="Snippet.form_elements"> <input id="textField" type="text"/> <select id="selectField"> <option></option> <option></option> <option></option> </select> <input id="hidden" type="hidden"> <input type="submit"/> </form>
Selectors
I also want to say a few words about the way of “binding” server variables to View. To do this, use the mechanism of selectors, which is very similar to real css-selectors. Here are a couple of examples:
Finding an element with id = "elemid" and setting its attribute "class"
def snippet = "#elemid [class]" #> "someclass"
With the "&" method you can combine several selectors.
def snippet = { "button [onclick]" #> Alert("some reaction") & "button [class]" #> "someclass" }
In order to transfer XML to the method, which selectors need to be changed, a lift attribute should be added to the appropriate tag (there are other ways, but I like this one most), which specifies the snippet that will process this XML.
<div lift="Snippet_class.snippet"> <button> </button> </div>
In my opinion, this is an ideal-concise way of linking logic and representation. The presentation doesn't touch at all (only the lift tag is added), the logic in the snippet is read very easily. The designer only needs to not touch the “lift” tags.
Configuration
All configuration is done on Scala. This means that you do not need to implement 40% of your code in XML files to create a flexible configuration. It also means that the compiler will prompt you if you have somewhere specified an invalid parameter in the configuration. This is very convenient when the project has a large and long configuration.
Security
The elevator guarantees
protection against many common vulnerabilities according to the
OWASP version. The funny thing is that you do not need to do anything for this, it is enough just to write code on the Lift. Here is what Rasmus Lerdorf (the person responsible for security on Yahoo) says about FourSquare (a project that is completely written in Lift):
“I couldn’t find out if I could find it”
twitter.com/rasmus/status/5929904263 .
This means that the developer does not need to worry about security and can concentrate fully on business logic.
Ajax support
Here's how to implement a regular ajax button:
class Snippet { def button = { def process() = { println(" "); Alert(" , ") } "button [onclick]" #> SHtml.ajaxInvoke(process) } }
And xml template:
<button lift="Snippet.button"> - </button>
Clicking the button will initiate an ajax call to the server, the process function will be called on the server, and a javaScript response will return. Minimum code, maximum logic. This principle can be traced throughout the framework.
Comet support
Lift has very good support for Comet, it is practically the pride of the framework. Here is how a simple example of clocks that are updated from the server every 10 seconds will look like:
object Tick class Clock extends CometActor { Schedule.schedule(this, Tick, 10 seconds) def render = "#time *" #> now.toString override def lowPriority = { case Tick => val js = SetHtml("time", Text(now.toString)) partialUpdate(js)
Template
<div lift="comet?type=Clock"> <span id="time"></span> </div>
Thanks to the excellent support of comets, such complex things as deferred loading are implemented very simply. On the required content, you need to call the built-in snippet LazyLoad. At the same time in our snippet, which creates content, you do not need to change anything.
<div lift="LazyLoad"> <div lift="Snippet.lazy_content"> - , </div> </div>
Snippet:
def lazy_content = { Thread.sleep(3000)
Compactness
When you write on Lift, you write 2-3 times less code than if you wrote on a java-framework (for example, one programmer rewrote his project from Play to Lift, his implementation took 24k lines on Play, and 6k to Lift) . And if you compare with frameworks like Spring MVC / Struts, the difference will be even greater. And all the code is statically typed.
Conclusion
I described only a small part of the functionality. In one article, it is impossible to disclose all aspects of such a large framework. For those who want to dig deeper here are the links:
liftweb.net - the main site
www.assembla.com/wiki/show/liftweb - wiki
exploring.liftweb.net/onepage - a book written by the framework's author