How to call Scala code from the browser.

120 views
Skip to first unread message

Diego Medina

unread,
Jun 20, 2011, 2:21:33 PM6/20/11
to Lift
Hi,

While I was reading some old posts on this list about back button
support for ajax based lift applications, I came across this thread
http://groups.google.com/group/liftweb/browse_thread/thread/fc0f9983ba050614
There, Alex Boisvert suggested a way to implemented which sounds
pretty interesting, but I guess he never had the time to implement it.

I have a particular question, I know that Lift has a mechanism for
calling server side scala code from the browser, could anyone point me
to where I should look to see how it is all done?

I would like to try an implement what Alex proposed, or at least get
something close to. I know that there are some requirements to get
code into Lift, but I'll enjoy the scala exercise :) (and maybe it
could be a module).

Thanks

I'm copying Alex's proposal here:

============

Just thinking out loud as to how this could work...
On modern browsers, it's possible to monitor the state change of the
browser's URL hash (aka window.location.hash / '#' / document fragment) in
the browser with the 'onhashchange' DOM event. It gets fired whenever the
location.hash changes. On older browsers, it's also possible to poll for
change which is less efficient but that's life.
So the idea would be to:
1) add a snippet or utility method to set up a listener on onhashchange that
would callback Scala functions associated with given hash (e.g. #foo, #bar,
...). Hashes could support parameters too (e.g., #foo/:param1/:param2)
2) add a method S.ajaxHash(hashPath, callback): JsCmd that would bind a hash
path/pattern to a Scala function (by registering the path/pattern with the
listener)
3) add a method S.changeHash(hashPath, params): JsCmd to programmatically
change the browser's hash as a result of some AJAX processing.
I don't have time to work on this yet but I'd be happy to hear what others
think of the idea.
alex

============


--
Diego Medina
Web Developer
http://www.fmpwizard.com

Antonio Salazar Cardozo

unread,
Jun 20, 2011, 2:43:06 PM6/20/11
to lif...@googlegroups.com
SHtml.ajaxCall will return a (String, JsExp) pair. It can bind to a server-side function, with JsExp being the JS that must be run on the client to invoke it.

We have a slightly more decorated version in our codebase:

  class CallableFunction(name:String, callback:(String)=>JsCmd, args:List[String] = List()) extends JsCmd {
    override val toJsCmd =
      Function(
        name, args,
        ajaxCall(JsVar(args.mkString("|")), callback)._2
      ).toJsCmd
  }

Used:

  case class LoadMoreChats(callback:(String)=>JsCmd) extends CallableFunction("loadMoreChats", callback, List("skip"))

  LoadMoreChats(loadMoreChats _) 

  private def loadMoreChats(skip:String) : JsCmd = {
      
    PrependChats(renderedChats)
  }

Antonio Salazar Cardozo

unread,
Jun 20, 2011, 2:46:46 PM6/20/11
to lif...@googlegroups.com
Eh, sorry, posted too fast. Anyway, PrependChats is a JsCmd that gets run on the client in response to the call.

We have a different approach to AJAX page switches, which degrades to regular link handling if there is no AJAX. In particular, we progressively enhance the page using jQuery Address (http://www.asual.com/jquery/address/). Server-side, pages that may be fetched via AJAX are wrapped in a Layout snippet that is similar to Lift's surround snippet. However, this snippet checks whether the incoming request is an XmlHttpRequest (via the X-Requested-With header) and strips the layout entirely if it is, returning the naked template without its wrapping document. If the request is a regular request, it does the usual wrapping.

The only caveat that makes it hackier than I would like is that the pages sent down are rendered by Lift in their own function domain, meaning they have their own GC id. We had to do send down that id (similar to how Lift did once upon a time) and modify the lift GC heartbeat code a little bit to accomodate that fact.
Thanks,
Antonio

Diego Medina

unread,
Jun 20, 2011, 10:38:26 PM6/20/11
to lif...@googlegroups.com
Thanks Antonio, I'll try this and post back with more questions :)

Diego

> --
> You received this message because you are subscribed to the Google Groups
> "Lift" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/liftweb/-/5SxhUqHOApkJ.
> 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.

Diego Medina

unread,
Jun 21, 2011, 12:28:38 AM6/21/11
to lif...@googlegroups.com
Wow, this turned out a lot easier than what I thought, Thanks to
Antonio's suggestion of using ajaxCall I can get rid of using a REST
interface and have back button plus bookmark'able urls on ajax /comet
based lift applications.

Now I have to sleep but I'll clean up the code of the sample
application I am playing with and I'll post back.

Thanks!!

Diego

Antonio Salazar Cardozo

unread,
Jun 21, 2011, 1:54:01 PM6/21/11
to lif...@googlegroups.com
Awesome! :)
Antonio
Reply all
Reply to author
Forward
0 new messages