Created
February 8, 2012 08:55
-
-
Save sofoklis/1766971 to your computer and use it in GitHub Desktop.
lift json autocomplete snippet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.liftweb.http._ | |
import S._ | |
import js._ | |
import JsCmds._ | |
import JE._ | |
import net.liftweb.textile._ | |
import net.liftweb.common._ | |
import net.liftweb.util._ | |
import Helpers._ | |
import scala.xml._ | |
import net.liftweb.json._ | |
import net.liftweb.json.JsonParser._ | |
import com.papasofokli.snippet.JsonAutocomplete._ | |
import net.liftweb.json.Serialization.{ read, write } | |
class JsonAutocomplete extends Loggable { | |
/** | |
* Create the json call, the createJsonFunc takes a partial function that | |
* handles the incoming request. | |
*/ | |
val (call : JsonCall, jsCmd : JsCmd) = S.createJsonFunc(receiveJson) | |
/** | |
* Partial function that takes care of the incoming request and redirects to the corresponding handler, | |
* Here you are matching directly on the json object defined bellow, you can have various case classes | |
* and respond accordingly for each request. Hhere i have only 2 kinds of json request, everything | |
* else goes to the log | |
*/ | |
def receiveJson : PartialFunction[JsonAST.JValue, JsCmd] = { | |
case st : JsonAST.JValue ⇒ st.extractOpt[SearchTerm] match { | |
case Some(SearchTerm(term)) ⇒ findTerms(term) | |
case None ⇒ st.extract[IdNameCategory] match { | |
case idc : IdNameCategory ⇒ handleIdNameCategory(idc) | |
} | |
} | |
case any ⇒ logger.info("anything else goes to the log" + any.toString) | |
} | |
/** | |
* Create a javascript to call the function to call the server with the right parameters, | |
* unfortunately i cannot use the generated one since it doesn't provide the success function | |
*/ | |
val functionDef = JsRaw("function " + | |
call.funcId + "(obj, onSuccess, onError) {liftAjax.lift_ajaxHandler('" + | |
call.funcId + "='+ encodeURIComponent(JSON.stringify(obj)), onSuccess, onError);}") | |
/** | |
* Add the implicit formats for the de/serialization | |
*/ | |
implicit val formats = DefaultFormats | |
/** | |
* My simple find function simply returns the value i need to show on the client. | |
* Here i am using the fantastic lift json support to serialize the case class | |
* and send it. The only problem was i could not find a way to send back a json object. | |
*/ | |
def findTerms(term : String) : JsCmd = { | |
val items = dropDownList.filter(_.value.contains(term)) take 10 | |
val ast = net.liftweb.json.Extraction.decompose(items) | |
JsRaw(write(ast)) | |
} | |
/** | |
* Simple handler, can write to database or anything else, now i am just sending an alert. | |
*/ | |
def handleIdNameCategory(idc : IdNameCategory) : JsCmd = Alert("received " + idc.toString) | |
/** | |
* Render function simple replaces the script | |
*/ | |
def render : CssSel = script | |
/** | |
* Register the callbacks on the autocomplete, very similar to the original code from | |
* jQueryUI autocomplete | |
*/ | |
def script : CssSel = "#script" #> Script(functionDef & JsRaw(""" | |
$(function() { | |
var items = []; | |
function log( message ) { | |
$( "<div/>" ).text( message ).prependTo( "#log" ); | |
$( "#log" ).scrollTop( 0 ); | |
} | |
$( "#city" ).autocomplete({ | |
delay: 1000, | |
source: function( request, response ) { | |
// I had to do this so i can pass the success and on error functions | |
""" + call.funcId + """({'term': request.term }, | |
//On Success | |
function(items){ | |
// Unfortunately i had to make this hack since i could not return a json from my snippet | |
items = items.replace(/[\n;]/g, ""); | |
response(JSON.parse(items)); | |
}, | |
//On error | |
function(){ | |
items =[]; | |
response(items)} | |
); | |
},""" + | |
""" | |
minLength: 2, | |
select: function( event, ui ) { | |
""" + | |
call.funcId + "(ui.item);" + | |
""" | |
}, | |
open: function() { | |
$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" ); | |
}, | |
close: function() { | |
$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" ); | |
} | |
}); | |
}); | |
""")) | |
} | |
object JsonAutocomplete { | |
/** | |
* Case classes to be used for the messages between the client and server, very easy to | |
* serialize and parse | |
*/ | |
case class IdNameCategory(val label : String, val value : String, val category : String) | |
/** | |
* Simple query for a search in the snippet | |
*/ | |
case class SearchTerm(val term : String) | |
/** | |
* Generate some items to check how it works | |
*/ | |
val dropDownList = for (i ← 0 to 8000) yield IdNameCategory("item" + i, "item" + i, "cat" + (i % 5)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment