Building a paginated search form - where do I store query state?

68 views
Skip to first unread message

Hristo Deshev

unread,
Oct 21, 2010, 5:21:53 PM10/21/10
to lif...@googlegroups.com
Hi all,

A Lift and Scala newbie here. I'm trying to build a pretty regular search form that lets you search for some data and displays the results in a paged table. 

I have a snippet class with two methods: search and list. Search builds a POST-submitted form that collects query criteria from the user (currently a simple search string from a text box). List, on the other hand, fetches the data from the DB using the query criteria to filter it. My snippet inherits from PaginatorSnippet[T] and the list method uses a template to build a paged table. My problem is that I don't know how to store my query state. Here's what I've tried so far:

 * A RequestVar - it's all fine until I click a page link generated by the PaginatorSnippet[T].paginate method. That does a GET request and my RequestVar disappears.
 * I tried turning my snippet into a StatefulSnippet. Again, the same problem - clicking the pagination links doesn't POST (of course!) the stateful snippet hidden input and the search value disappears.
 * A SessionVar - that seems to work. The only downside is that my state is there forever and when I navigate away from the site, and then come back, my search criteria stay the same as before. Ideally I'd like those to be reset.

It looks like I'm trying to build something pretty common, and I'm doing something wrong. Can somebody point me to the best way to store search criteria across requests? Maybe I have to plug into the way PaginatorSnippet generates paging links, but the *pageUrl* overridable method returns a string and I seem to need a closure that would get executed on the next request to, say, load a RequestVar with the proper object.

Thanks,
Hristo

Naftoli Gugenheim

unread,
Oct 21, 2010, 5:47:32 PM10/21/10
to liftweb
Are you using a sorted paginator? If so, mix in StatefulSortedPaginatorSnippet.
If not, in your Paginator:
override def pageUrl(offset: Long) = S.fmapFunc(S.NFuncHolder(() => registerThisSnippet)){ name =>
        Helpers.appendParams(super.pageUrl(offset), List(name -> "_"))

where, if you're using a StatefulSnippet, registerThisSnippet refers to the method on the StatefulSnippet.
If you want to use RequestVars, try something like this:
override def pageUrl(offset: Long) = {
  val currentState = myRequestVar.is
  S.fmapFunc(S.NFuncHolder(() => myRequestVar(currentState))){ name =>
        Helpers.appendParams(super.pageUrl(offset), List(name -> "_"))
}

This is not tested in any way.


--
You received this message because you are subscribed to the Google Groups "Lift" group.
To post to this group, send email to lif...@googlegroups.com.
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.

Hristo Deshev

unread,
Oct 22, 2010, 5:14:31 AM10/22/10
to lif...@googlegroups.com
Hi Naftoli,

I used the RequestVar version:

On Fri, Oct 22, 2010 at 12:47 AM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
If you want to use RequestVars, try something like this:
override def pageUrl(offset: Long) = {
  val currentState = myRequestVar.is
  S.fmapFunc(S.NFuncHolder(() => myRequestVar(currentState))){ name =>
        Helpers.appendParams(super.pageUrl(offset), List(name -> "_"))
}


and it worked like a charm. Thanks a bunch! I also found this article on the wiki that was quite illuminating with regards to what fmapFunc does: http://www.assembla.com/wiki/show/liftweb/Mapping_server_functions_to_client_actions.

On a side note, why does fmapFunc take a function that takes the mapped function name as a parameter instead of just returning the name? Code like this:

val baseUrl = super.pageUrl(offset)
val name = S.fmapFunc(S.NFuncHolder(() => myRequestVar(currentState)))
appendParams(baseUrl, List(name -> "_"))

seems a lot simpler to me (maybe because the Scala is still weak with me). Is that second function there to try and make it harder for people to take a hold of the generated name, stuff it in the session and do dumb things with it?

Hristo
Reply all
Reply to author
Forward
0 new messages