I'm attempting to write in Scala Lift a page that renders a list of items (proposals), and allows a button next to each to be clicked to take a verification action on that item. The approach I'm taking is to render a form for each item, and have it capable of taking an ajax action on that item. The page is rendering fine, except that the javascript scripts seem to not be rendering for each individual form.
This is my starting html:
<div class="lift:Verify.list" >
<ul>
<li class="proposal jsonForm" data-lift="Verify">
<script class="jsonScript" data-lift="tail"></script>
<div>
<span class="name">Name</span> is <span class="verified">quantumly verified.</span><input type="submit" value="Verify"/><span class="result"/>
</div>
</li>
</ul>
</div>
And this is my verification object:
object Verify extends Logger {
val proposals:List[Proposal] = Proposal.findAll
def list = ".proposal *" #> proposals.map { p =>
".name" #> p.name &
".verified" #> { p.verified.get match {
case true => "verified."
case false => "UNVERIFIED."
}}
}
def render = ".jsonForm" #> ((ns:NodeSeq) => jsonForm(VerificationServer, ns)) &
".jsonScript" #> Script(VerificationServer.jsCmd)
object VerificationServer extends JsonHandler with Loggable {
def apply(in: Any):JsCmd = in match {
case JsonCmd("processForm", target, params: Map[String, String], all) =>
SetHtml("result", Text("Verified"))
}
}
}
When I view source after the page renders (with three proposals being loaded up), I'm seeing this at the bottom:
<script src="/ajax_request/liftAjax.js" type="text/javascript"></script>
<script class="jsonScript"></script>
<script class="jsonScript"></script>
<script class="jsonScript"></script>
<script type="text/javascript">
// <![CDATA[
var lift_page = "F1026676301564EIZULQ";
// ]]>
</script>
The empty <script class="jsonScript"></script>
seems to be the problem: in a page with a single form, this contains something looking like this:
<script type="text/javascript" id="jsonScript">
// <![CDATA[
function F590130389017U5BRNC(obj) {liftAjax.lift_ajaxHandler('F590130389017U5BRNC='+ encodeURIComponent(JSON.stringify(obj)), null,null);}
// ]]>
</script>
I'm (obviously) very new to Lift, and may not be doing this the best way. If there is a better way to accomplish the goal, what is that? And if this is a reasonable path, why is it that those script tags are not being populated?
I'm not sure exactly the output you are looking for, but there seem to be a bunch of things that work in your example. For example, SetHtml
requires and ID, but you are passing in a class. Also, your script
tag is calling a method tail
in the snippet which doesn't appear in your code.
That said, something like this should allow you to do what I think you are looking to do:
class TestSnippet {
/** A definition of the Proposal class we will use *//
case class Proposal(val id:Long, val name:String, var verified:Boolean)
val proposals = //Define collection here
def render = ".proposal" #> proposals.map { p =>
"div [id]" #> s"prop-${p.id}" &
".name" #> p.name &
".verified" #> {
p.verified match {
case true => "verified."
case false => "UNVERIFIED."
}
} &
".submit" #> SHtml.ajaxButton("Verify", () => {
p.verified = true
JsCmds.Run("$('#prop-" + p.id + " .result').empty().html('" + p.verified + "')")
})
}
}
And apply it to the HTML
<div>
<ul data-lift="TestSnippet">
<li class="proposal">
<div>
<span class="name">Name</span> is <span class="verified">quantumly verified.</span><input type="submit" class="submit" value="Verify"/><span class="result"/>
</div>
</li>
</ul>
</div>
What this will do is iterate through your proposals
collection and for each item, set the id
attribute of the container div
to a unique value (here I assume a Proposal
has an id
field) so jQuery
can easily refer to it. Then, I bind an ajaxButton
to your submit tag in the same CSSTransform
that we output name
and verified
. When clicked, the button will set the verified field to true
and then execute some JavaScript on the client - in this case it is a jQuery
expression which looks for the div whose id
we assigned and sets the text in the result
span to the value of p.verified
.
So, the page would initially render like this:
And clicking on a button would yield this:
For more complicated updating, such as if you wanted to have "UNVERIFIED" change to "verified" lift also provides a few built-in Memoization functions that can help in re-rendering the CSS Snippet. You can see more about it here, here, and in bunch of discussions on the Lift mailing list.