1
votes

I'm starting out with Lift and been reading a few tutorials and books that are available online. Coming from a JSP (or GWT) background, it's a huge leap, especially since I'm still learning Scala too.

Anyway... I've created the basic site by downloading the lift tar.gz stuff from their site, copied the lift_blank" directory and renamed it to "test". Did the whole "sbt update ~jetty-run" thing etc etc.

What I want to do is modify the "index.html" page to simply have a text field for input, and a button that says "search". Basic idea, you type your firstname, hit "Search", a database query is executed for finding records with a firstname of "what-you-entered-in-the-text-field", and then the results are formatted and displayed on the web page; after the page has refreshed, the text field needs to contain the name that was entered as well.. You type in a different name, hit "search", and new results are displayed on the page. Initially (first time visiting the page), the results are of course empty. Simple stuff...

However, the examples I've all seen use html forms and POST backs etc; I really dislike this, for example users get all flustered when refreshing the page and they get a firefox popup "To display this page, Iceweasel must send information that will repeat any action (such as a search or order confirmation) that was performed earlier."... the page is also refreshed which is something I'd like to avoid.

Previously when I would build this in JSP, I would use all javascript; no "form" tags or anything, just a simple field with javascript events for hitting enter or hitting a "button"... events thaen get channeled to a main javascript function "onQuery" which then creates an AJAX request; when the result comes back from the server, javascript would modify a wrapper "div" element by changing the "innerHTML" value etc. The nice thing here is that the page doesn't refresh, just a tiny subsection of it does, the "table" (actually a div) which holds the results.

How would I re-create a very similar thing in Lift? I'm kind of lost here. I've followed a few examples in the past few days, but again they all use POST / forms. I can handle the scala database querying, and I understand how Lift's templates works, it's just the snippet / comet stuff that I could use a few pointers on.

2

2 Answers

2
votes

You can try to use the SHtml.ajaxText function to get the input and to use Wiring on server's side to deal with the request and change automatically the result.

However, with this solution, you no longer need the submit button, but as you don't want a form it should not matter much.

Here is what I think about for the HTML file :

<div id="myHtml" class="lift:surround?with=default;at=content">
    <form class="lift:form.ajax">
        <input class="lift:SearchForm.name"/>
    </form>
    Value searched : <span class="lift:SearchForm.display">
</div>

Now on server's side it is a little bit more complicated

class SearchForm{
  val name = SHtml.ajaxText("", s=>{ SearchWiring.name.set(s); Noop})

  def display = {
     WiringUI.apply(SearchWiring.name)(name:String => {"*" #> name} )
  }
}

object SearchWiring{
    val name = ValueCell("All")
}

I don't know if this is totally rigorous but it is my best thought for your problem. You will find more details about wiring on the official liftweb demo and on Seven Things blog. I hope it will help!

0
votes

Below is what I ended up using. The one thing I dislike about Lift is all the "magic" that needs to be inserted at various points. I can understand most of this, but the whole " ++ hidden" thing could use some explaining...

The "index.html" page, everything including the "body" tag:

<body class="lift:content_id=main">
    <div id="main" class="lift:surround?with=default;at=page">
            <lift:Search.search>
                    Search Query: <query:text/>&nbsp;<query:button/><br/>
                    <div id="results">
                    </div>
            </lift:Search.search>
    </div>
</body>

The "Snippet" code, in a class called "Search.scala" (some of the import statements are unused, a leftover result of attempting different approaches):

package code
package snippet

import scala.xml.{NodeSeq, Text}
import net.liftweb.util._
import net.liftweb.common._
import java.util.Date
import code.lib._
import Helpers._
import common.Main
import common.solr.{Hitlist, Solr}
import net.liftweb.http.{S, StatefulSnippet, SHtml}
import net.liftweb.http.js.JsCmds.SetHtml

import _root_.net.liftweb.http.SHtml._
import _root_.net.liftweb.util.Log
import net.liftweb.http.js.JsCmd
import net.liftweb.http.js.JE.JsRaw

object Search {
    def search(xhtml:NodeSeq):NodeSeq = {
        var queryText = "(initial)"

        def runQuery() = {
            println("\n\nQuery: " + queryText)
            SetHtml("results", <span>Query: {queryText}</span>)
        }//runQuery

        ajaxForm(
            bind("query", xhtml,
                "text" -> text(queryText, queryText = _),
                "button" -> submit("Post", runQuery)
            ) ++ hidden(runQuery _)
        )
    }//search
}//Search