Question

I use SetHtml() all the time to swap chunks of HTML as part of the return trip of an ajax call, ie. when my "Edit Item" ajax call returns, I swap the contents of with form elements representing the "Item" to be edited.

Now I'm trying to add a new item to a list (so that "Item 2" appears as the next li under "Item 1"). My html looks like (this is a greatly simplified version) this:

<div data-lift="form.ajax">
    <div data-lift="JsCmdTest">
        <test:submitbutton></test:submitbutton>
        <ul id="targetdiv">
            <li>Item 1</li>
        </ul>
    </div>
</div>

and my Lift code looks like this

class JsCmdTest extends StatefulSnippet
{
  def dispatch = { case "render" => render }
  def bindStuff(ns: NodeSeq): NodeSeq =
  {
    bind("test", ns,
      "submitbutton" -> SHtml.ajaxButton("Go", ()=> {
          val newLi = Jx(<div>Item 2</div>)
          (ElemById("targetdiv") ~> JsFunc("appendChild", newLi.toJs)).cmd
      })
    )
  }
  def render: (NodeSeq)=>NodeSeq = (ns: NodeSeq) => {
    bindStuff(ns)
  }
}

When I run this, the ajax call is fired, and the response looks fine, but I get the following error in the browser console:

The server call succeeded, but the returned Javascript contains an error: NotFoundError: Failed to execute 'appendChild' on 'Node': The new child element is null.

WANTED: a way to append replacement HTML to an existing < ul >. I feel like the way I'm going about appending seems way more esoteric than probably needed, but i haven't found any other way to do it.

Thanks in advance!

Was it helpful?

Solution

  • you're using a very old syntax for binding. If I am not mistaken, a new way for bindings was introduced somewhere in lift-2, and it is the recommended one since somewhere in lift-2.2. (I'll write the syntax below.)

  • JsFunc is an anonymous function, like def local(a: A): B. You don't need to send anonymous function, you can send the code directly. (See below.)

  • So, I recommend something like this:

import net.liftweb.http.js.{JsExp, JsCmd, JsCmds}

import net.liftweb.http.js.jquery.JqJE.{JqAppend, JqId}

def render = {
    val appendJs: JsExp = JqId("targetdiv") ~> JqAppend(newLi)
    "#mySubmitButton" #> SHtml.ajaxButton("Go", () => appendJs.cmd)
}

You'll also have to adapt the HTML a little, like using a normal <button> with id="mySubmitButton".

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