The key difference that took me a while to pick up on between Lift and
other template systems i'd used (JSP, ASP, ASP.net) is that Lift is
just transforming XML.
The snippet methods take XML as input, and return XML. Things get
interesting because:
1. the snippet can ignore the input XML and return whatever it wants,
def foo(xhtml: NodeSeq): NodeSeq = <h1>foo</h1>
2. the snippet can repeat the input xml out many times using flatmap
and bind, e.g.
def foo(xhtml: NodeSeq): NodeSeq = List(1,2,3).flatMap { n =>
bind("foo", xhtml, "number" -> n.toString) }
usage:
<lift:MySnippet.foo>
<b><foo:number/></b>
</lift:MySnippet.foo>
output:
<b>1</b>
<b>2</b>
<b>3</b>
3. The snippet can wrap the input as I showed before
def foo(xhtml: NodeSeq): NodeSeq = <p> {xhtml} </p>
4. The snippet can even read the input as parameters if it wanted (not
recommended)
def foo(xhtml: NodeSeq): NodeSeq = { <b>Input contained { (xhtml\
\"div").length } divs</b> }
5. you can also do multiple levels of binding and repeating
def foo(xhtml: NodeSeq): NodeSeq = {
val items = List((1,"a"), (2,"b"), (3,"c"))
def bindItems(xhtml: NodeSeq): NodeSeq = {
items.flatMap { case (number, letter) =>
bind("item", xhtml,
"number" -> number.toString,
"letter" -> letter
}
}
bind("stuff", xhtml,
"label" -> "MyStuff",
"items" -> { (node: NodeSeq) => bindItems(items) }
)
}
usage:
<lift:MySnippet.foo>
<h1><stuff:label/><h1>
<ul>
<stuff:items>
<li><b><item:number></b>: <item:letter></li>
</stuff:items>
</ul>
</lift:MySnippet.foo>
output
<h1>MyStuff</h1>
<ul>
<li><b>1</b>: a</li>
<li><b>2</b>: b</li>
<li><b>3</b>: c</li>
</ul>