Version 4, last updated by marius.danciu at 20 Jan 00:18 UTC
More on Snippets
For basic information on how to use snippets to bind content read Templates and Binding
This wiki entry was originally written by Timothy Perrett and was lifted with permission from his blog which can be found at blog.getintheloop.eu
One of the confusing things about Lift for new comers are snippets – not only conceptually, but the bewildering array of options they have when choosing snippet implementation style. Users have to choose between snippet reflection, dispatch snippets and even stateful snippets that extend snippet dispatching!
Reflection Snippets
Loading class-based snippets via reflection is the default scheme in Lift as it offers a quick start for development. Given the following code in my snippet package:
import _root_.scala.xml.{NodeSeq,Text}
class HelloWorld {
def speak = <span>Hello World</span>
}I could then just call this in any Lift template I wanted by using the following:
<lift:hello_world.speak />
So right there, with no other plumbing we have a working snippet invocation – granted, our example is not feature full but it services our needs for this example. So this is all great, and works perfectly for development / low volume deployment, however when your site starts to scale this method of snippet modeling may become undesirable. Why? Firstly, the binding between tag names and methods is fixed. Also, some consider using dispatch snippets the best practice because it’s clearer to other team members. A possible small performance hit is moreover that at most one reflection call per request will happen to find the snippet implementation and method.
A new instance of a reflection snippet is created at most once per http request, so if you use the same snippet multiple times on a page, only one instance will be created. The instances are stored in a RequestVar, so the lifetime of such snippets spans the http request and any ajax callbacks that your page may make. Essentially, the lifetime of the snippet is equal to the lifetime of a rendered page.
DispatchSnippet to the rescue!
With DispatchSnippets, you have control over the binding between tag names and the methods. All we need to change in our example is extending the DispatchSnippet trait and implementing a dispatch method:
import _root_.scala.xml.{NodeSeq,Text}
import _root_.net.liftweb.http.DispatchSnippet
class HelloWorld extends DispatchSnippet {
def dispatch = {
case "talk" => speak
}
def speak = <span>Hello World</span>
}The dispatch method may contain logic in which you can decide which method should be called. The logic can use S (the current state) etc. Still, a new instance of the snippet will be created per request.
Singleton DispatchSnippets
In Scala we can of course use the object keyword to create a singleton object – this is most helpful in terms of snippets, as comparatively to creating lots of instances, here we will only have a single one which makes for a much more optimal snippet system. Let’s take our previous snippet and turn it into a singleton dispatch snippet:
import _root_.scala.xml.{NodeSeq,Text}
import _root_.net.liftweb.http.DispatchSnippet
object HelloWorld extends DispatchSnippet {
def dispatch = {
case "talk" => speak
}
def speak = <span>Hello World</span>
}There is of course a slight downside – the reflection snippets mean no plumbing, but with the DispatchSnippet we will of course just need to let Lift know when we call something in our XHTML what snippet instance we are referring to – we do this with a SnippetDispatchPF call in your Boot.scala file:
LiftRules.snippetDispatch.append(
Map("hello_world" -> HelloWorld)
)This means in our XHTML we can call:
<lift:hello_world.talk />
This has the exact same output as the reflection style snippet, but only using a single snippet instance for your application.
StatefulSnippets
You can control the lifetime of stateful snippets, so that they may survive multiple request. Other frameworks often use the term “conversation scope”. They are useful for example when creating multi-page wizards.
A StatefulSnippet extends DispatchSnippet, so you will need to implement the dispatch method. Also, when generating links, you will need to use the link method from StatefulSnippet, instead using the one from S.
After you no longer need the snippet instance, just call unregisterThisSnippet() from the snippet’s method.
For more details refer to the book.
AttributeSnippets
Sometimes it is useful to use dynamic constructed attributes to existent nodes. For instance:
<div class="badWheather">
...
</div>
We don’t really care about the div content, but sometimes we want this div to have the CSS class ‘goodWheather’. This an attribute snippet comes to the picture:
<div lift:MyClass.meteo="badWheather">
...
</div>
and the Scala code:
class MyClass {
def meteo(in: MetaData): MetaData = {
// here return your metadata, probably an UnpreffixedAttribute
}
}
Observe that this is a MetaData => MetaData and not a NodeSeq => NodeSeq type. Obviously because we want to deal with node attributes and not XML nodes.