tags:

views:

62

answers:

1

Hi all,

Pardon my excruciatingly simple question, but I'm quite new to the world of Lift (and Scala, for that matter).

I'm following the "Getting Started" tutorial on the Lift website: http://liftweb.net/getting_started

I've got it up and running but I'd like to make a quick modification to the app so that every time I press enter in the textbox, it maintains focus. I've managed to get it to focus on page load using FocusOnLoad but I can't quite figure out how to get it to keep focus (using only Lift's classes, no custom JavaScript).

Here's what my def render method (the bind part) code looks like:

def render =
    bind("chat", // the namespace for binding
    "line" -> lines _, // bind the function lines
    "input" -> FocusOnLoad(SHtml.text("", s => ChatServer ! s)) )

So that works for getting it to focus upon page load. But since this is a Comet app, the page only loads once.

All my other code looks exactly like the tutorial FWIW.

+1  A: 

The render method in a CometActor only gets called when the CometActor is first initialized, which happens when the user first goes to the Chat page. Afterwards, the page updates usually happen inside of the lowPriority or highPriority methods. So if you want the text box to become focused after the user sends an AJAX update to the CometActor, you should add it to one of those methods. An example which uses JQuery would be this:

override def lowPriority = {
  case m: List[ChatCmd] => {
    val delta = m diff msgs
    msgs = m
    updateDeltas(delta)
    partialUpdate((JqJE.Jq(JE.Str("input[type=text]")) ~> (new JsRaw("focus()") with JsMember)).toJsCmd)
  }
}

I haven't tried compiling this, so it might need some slight tweaking. Essentially, it's just sending another JavaScript command to the browser that uses JQuery to find a text input on the page and then sets the focus on that control. If there are multiple text inputs, you'll need to modify the class on the HTML template for the control you want to set focus on, then make sure that you change your render method to be:

def render = 
  bind("chat",
       "line" -> lines _,
       "input" -%> FocusOnLoad(SHtml.text("", s => ChatServer ! s)) )

The -%> method instructs Lift to not ignore any attributes in the template during the bind phase. Then you can modify the JQuery selector to use that class to find the right control to focus on. Part of the form security in Lift obscures the ID assigned to forms and their controls to prevent XSS attacks, so it's generally better to use class selectors to find form controls using JQuery or some other Javascript framework.

Aaron
This makes sense I think, I'll give this a try. By the way, what does the ~> method do? And where would I learn more about other methods like -%> ? I'm trying to avoid using an IDE to learn Scala (straight up Textmate instead) so I don't get the benefit of drilling into methods.
Aashay Desai
The `~>` method is defined on the `net.liftweb.http.js.JsExp` trait and it accesses a property of a JsExp. I use it above to call the `focus` method on the jQuery object that is returned by the jQuery selector which I created with the JqJE.Jq(JE.Str("input[type=text]")) method. Those calls create the Javascript "jQuery('input[type=text]').focus();" The best way to find things like this is to look at the Lift Google Group and to dig into the source. Lift's sources are a really good way to learn Scala. Also look at the upcoming book Lift in Action over at http://manning.com/perrett.
Aaron
Since I ran out of room, the `-%>` method is defined in the `net.liftweb.util.SuperArrowAssoc` class. Unfortunately, there's not a lot of documentation in that class but it and the `net.liftweb.util.BindHelpers` class take care of all of that happens inside of the `bind` function that you call inside of the CometActor and inside of Snippets that you'll create. I definitely applaud you trying to learn Scala without an IDE. That's a great way to do it but it can be challenging at first since Lift uses many traits, it's sometimes hard to figure out where things are.
Aaron