Lift is a modern Scala language framework for creating web applications and offering non-standard approaches for solving some tasks. In this note, we will consider the simplest example of (before) downloading data from a server using AJAX requests. The post is written in the hope that it can be useful to someone and reduce the time to search for a solution for an hour or two, or simply as a demonstration of the capabilities of a great modern, but not very popular framework. But I assume that the reader already has some basic ideas about Lift and about some of the concepts used in it.
As an example, let's take an application that should display “comments” - when you load the page, the first five, and the rest of the load - on request, in “portions” of five pieces, without reloading the page, of course.
So, let's begin. Let us have a Post model that represents a single comment:
class Post extends LongKeyedMapper[Post] with IdPK { def getSingleton = Post object title extends MappedText(this) object text extends MappedText(this) object date extends MappedDate(this) }
and the corresponding companion object:
object Post extends Post with LongKeyedMetaMapper[Post] { def getPosts(startAt: Int, count: Int) = { Post.findAll(OrderBy(Post.date, Descending), StartAt(startAt), MaxRows(count)) } def getPostsCount = Post.count }
in which two functions have already been declared - getting the total number of objects and getting a certain adjustable range of comments. In our case, it was possible to do without these methods and build requests “in place” - right in the code of the snippets, but, in my humble opinion, this will make testing more difficult and will overload the code.
')
Now we need to do the initial display of comments. To do this, create the following snippet:
class PostRender { def renderPosts(in: NodeSeq): NodeSeq = { Post.getPosts(0, 5).flatMap(item => bind("post", in, "title" -> Text(item.title), "text" -> Text(item.text) )) } }
And the corresponding
embeded template that is located in /templates/__post.html (yes, underscores even in Scala / Lifft are sometimes needed):
<lift:PostRender.renderPosts> <p> Title: <post:title /> <br /> <post:text /> </p> </lift:PostRender.renderPosts>
and which connects to the desired page using:
<div id="posts"> <lift:embed what="/templates/__post" /> </div>
I want to note that in this case I use the “outdated” template markup, based on the spec. xml-tags, which in this case seems to me more convenient and intuitive.
As a result, after adding a model to the database schema, filling records, etc., we get something like this:

only 5 objects, as required. Now we need to organize the loading of the remaining comments.
AJAX download
Before we continue, a few words should be said about JsCmd - in fact, the subsystem in Lift, which is designed to generate client-side JavaScript on the server side, in the snippet code and then insert them into the response. There are various ways to inject JS code — from the JsRaw method, which allows you to insert raw JS, to proxy methods for JS frameworks. First of all, JsCmd is designed to implement small parts of JS-code.
Modify the insertion of comments by adding a call to the snippet to display the download button for additional objects:
<div id="posts"> <lift:embed what="/templates/__post" /> </div> <lift:PostRender.renderLoadMoreControl />
and the snippet class:
class PostRender { val loadSize = 5 val lastLoadIndex = Post.getPostsCount - loadSize var loadStartIndex = 0 def renderPosts(in: NodeSeq): NodeSeq = { Post.getPosts(loadStartIndex, loadSize).flatMap(item => bind("post", in, "title" -> Text(item.title), "text" -> Text(item.text) )) } def renderLoadMoreControl: NodeSeq = { def loadPosts: JsCmd = { loadStartIndex += loadSize JqJsCmds.AppendHtml("posts", <lift:embed what="/templates/__post" />) & { if (lastLoadIndex < loadStartIndex) JsCmds.Replace("loadButton", NodeSeq.Empty) } } SHtml.ajaxButton("Load More", loadPosts _, "id" -> "loadButton") } }
Values ​​were introduced into the class to represent loadable “pages” with comments — the
renderPosts method uses their original values ​​to display the first 5 entries, as well as the new
renderLoadMoreControl method, which adds a button to load the next “portion” of comments and links it to the internal
loadPosts function which is the implementation of the AJAX response. Consider it in more detail.
First of all, we increment the index count of the records to load - this is obvious. Next, we call the
AppendHtml method from the
net.liftweb.http.js.jquery.JqJsCmds package, which provides wrappers for jQuery library functions (which is built in by default in Lift).
AppendHtml takes two parameters — the id of the DOM tree object and an object of NodeSeq type — in fact, the code that will be added. I think it is now becoming clear why the comment template was moved to a separate file - now it can be transferred to the
AppendHtml method as an AJAX response, and moreover - this template will be processed using the
renderPosts ! Functions that return the JsCmd type can be concatenated using the
& method — in our case, when the last “page” is reached, the button for loading comments is hidden. Actually - that's all, all the code :)
On the client side, the button will turn into something like this code:
<button onclick="liftAjax.lift_ajaxHandler("F167386167581RGRLAG=true", null, null, null); return false;" id="loadButton">Load More</button>
, and the response code will contain jQuery commands, like this:
jQuery('#'+"posts").append("\u000a <p>\u000a Title: Post #11 ... ");
As a conclusion
Of course, this example is somewhat artificial, but it can demonstrate some features of Lift: built-in tools for creating AJAX requests, wrappers and proxy methods for creating client-side JavaScript, end-to-end processing of templates. Also, no client JS code was written at all at all - all this is taken by the framework, beyond which we did not go in this example. However, this is not the only approach, and if necessary, then of course there are no obstacles to "manual control". Application code can be obtained
here (used by Maven).