Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top