I'm looking for the best way to perform a "named" ajax request. I wrote a little trait that extends DispatchSnippet that, by way of SHtml.jsonCall, gives me something like
ajaxDispatch("setAppointment", { start:new Date(), end:new Date() });that returns to the browser the js to execute. This works well for js that I intend to execute, but I'd also like a way to simply get json from the server (yes, I know I could just append a dispatch pf to LiftRules.dispatch but I was hoping for something that I don't have to register during boot.
So, in my snippet, I'd like to simply use my AjaxDispatch trait that gives me something like:
def ajaxDispatch = {
// current use - returns js for creating a dialog box via blockUI
case "setAppointment" => json => {
json.extractOpt[CurrentCalendarSelection] match {
case Some(currentSelection) => SetAppointment.dialog(Empty, Empty, currentSelection);
case _ => Noop
}
}
// now, a json example
case "events" => json => {
json.extractOpt[CurrentCalendarView] match {
case Some(currentCalendar) => getEventsForCalendar(currentCalendar) // List[CalendarEvent]
case _ => JArray(Nil)
}
}
}
trait AjaxDispatch extends DispatchSnippet with Logger {
def ajaxDispatch: PartialFunction[String, JValue => JsCmd]
private implicit val _ajaxDefaults = DefaultFormats
def dispatch: DispatchIt = {
case "ajaxDispatch" => _ => Script(JsRaw("""function ajaxDispatch(_name){ if (!_name) { throw "Function name is required"; }; %s;}""".format(
SHtml.jsonCall(calcArgs, args => {
// TODO: when the patch from ticket #1070 is available in a release - use SHtml.ljsonCall and 86 this f
(for {
r <- S.request
(_, paramValue :: Nil) <- r.params.headOption // get the first and only parameter from the request
_json <- parseOpt(paramValue) // paramValue from js `JSON.stringify`
} yield processRequest(_json)) openOr Noop
})._2.toJsCmd
)).cmd)
}
// Split the json into name and value
private def nameAndValue(_json: JValue): Box[(String, JValue)] = {
_json.children.head.extractOpt[String] match {
case Some(funcName) => Full((
funcName,
(if (_json.children.length > 1) _json.children.tail.reduceLeft[JValue](_ ++ _) else JNull)
))
case _ => Empty
}
}
// TODO: when the patch from ticket #1070 is available in a release - use SHtml.ljsonCall
private def processRequest(_json: JValue): JsCmd = {
nameAndValue(_json) match {
case Full((f, j)) if ajaxDispatch.isDefinedAt(f) => ajaxDispatch.apply(f)(j)
case Full((f, _)) => {
val msg = "A matching function for '%s' could not be found.".format(f)
debug(msg)
if (Props.mode == Props.RunModes.Development) JsRaw("console.error(%s)".format(msg.encJs)).cmd
else Noop
}
case _ => {
val msg = "Missing ajax function name."
debug(msg)
if (Props.mode == Props.RunModes.Development) JsRaw("console.error(%s)".format(msg.encJs)).cmd
else Noop
}
}
}
protected val calcArgs: JsExp = JsRaw("Array.prototype.slice.call(arguments)")
}