"named" ajax

27 views
Skip to first unread message

Andrew Mullins

unread,
Feb 7, 2012, 1:20:22 PM2/7/12
to lif...@googlegroups.com
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
// javascript
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)
    }
  }
}

I could return the json in a variable assignment:
var events_json = [...]; // overwrites on each request

My current AjaxDispatch trait:
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)")

}

David Pollak

unread,
Feb 7, 2012, 1:44:02 PM2/7/12
to lif...@googlegroups.com
Andrew,

This issue has come up a number of times in the last few weeks.  Can you open a ticket on it and I'll add a convenience method to generate just such a function?

Thanks,

David
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Sofoklis Papasofokli

unread,
Feb 7, 2012, 2:03:29 PM2/7/12
to lif...@googlegroups.com
Hi David,

I was stuck on the same thing today, I would very much appreciate a way to do that.

Sofoklis
--
Sofoklis

Andrew Mullins

unread,
Feb 7, 2012, 3:42:58 PM2/7/12
to lif...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages