Lift has several ‘XVar’ classes for managing server-side state: ContainerVar, RequestVar, ScreenVar, SessionVar, TransientRequestVar, WizardVar.
They are all similar in their how they are used, and the mechanism by which data is held within them. They differ primarily by the lifetime of the data they contain.
To define, say, a
SessionVar, create a singleton that extends
object myData extends SessionVar[String]("Default")
In this case
myData is strongly typed as a
String. Only a
String may be put in or taken out. The expression
"Default" is the default value for the given
SessionVar. The expression is a passed “By Name” and is only evaluated whenever the
SessionVar is read before it is set.
To set the data:
To access the data:
A common pattern is to put the variable in a Box within the X Var, e.g:
object myModel extends SessionVar[Box[Model]](Empty)
This pattern allows you to avoid null testing, and instead use for comprehensions to traverse Box and Option constructs. See DPP’s Blog on the subject.
All XVar objects act as indices into a backing datastore. When you set, say, a RequestVar with something like nameRV(“Jo”), the set method creates an entry in a map, where the ‘key’ is based on the name of the variable (in this case, something like liftsvcode.snippet.NameSnippet$nameRV$), and ‘value’ is what we’re setting the RequestVar to (in this case ‘Jo’).
The backing datastores are global objects, and so are shared across all page requests, snippets, Ajax calls etc. So, if you have two XVar objects with the same name, in different scopes, they are in fact just acting as indices into the same datastore value (unless you have overridden the namesalt). So, in this sense, XVar objects appear to transcend the normal scope boundaries.
ContainerVars hold data with a lifetime nominally equivalent to the lifetime of HttpSession attributes. This alternative to SessionVar keeps data in the container’s session and must be serializable to support session migration. Use SessionVars unless you are using MigratoryLiftSessions.
RequestVars hold data with a lifetime nominally equivalent to the lifetime of a page rendered by an HTTP request. RequestVars maintain their value throughout the duration of the current HTTP request and any callbacks for servicing AJAX calls associated with the rendered page. RequestVar instances have no value at the beginning of request servicing (excluding AJAX callbacks) and their value is discarded at the end of request processing.
They are commonly used to share values across many snippets and to share data across successive page requests.
For more information on RequestVars see the blogpost: Understanding Lift’s RequestVar
A variable that is local to a particular rendering of a form generated by a LiftScreen. This is a much narrower scope than RequestVar!
ScreenVar is essentially a TransientRequestVar (a key into a datastore map) that is persisted via a hidden form field that is auto-generated by the Screen. This allows multiple instances of a screen to be used on the same page (and thus in the same request context) and each have a separate set of variables.
This also means that they will not participate in subsequent request interactions outside of the form (e.g. post-rendering AJAX). Basically, ScreenVar lets you work with a value through the normal processes of the screen (e.g. validations and finish will see the variable values correctly, since LiftScreen will re-populate the values as it processes the submitted form).
A sessionVar holds data lifetime nominally equivalent to the lifetime of HttpSession attributes.
A typical use of a SessionVar in Lift is to manage the User session, so repeated requests from the same browser will be associated with the same data. This allows the primary key to the User object to be associated with user’s perception of a session so that once the user has logged in, they do not need to re-authenticate for each HTTP request.
Sessions are typically bound between the browser and the server via a cookie which contains a session identifier… a random number.
A TransientRequestVar holds data with a lifetime strictly equal to the processing of a single HTTP request. Unlike ordinary RequestVar instances, TransientRequestVars will not maintain data for servicing of AJAX callbacks from a rendered page. This is useful in cases where the value stored within the RequestVar cannot safely be used across multiple requests; an example of such a value is a JTA UserTransaction which has a lifecycle strictly coupled to the actul HTTP request handling by the enclosing container.