Variables


Introduction

Variables look like this:

{$loggedinuser.firstname}

They can appear in Application templates, Wrapper templates, Email templates and within Components.

A good example of a variable is the {$loggedinuser.*} variable. This variable contains all user information of the currently logged in user. If you would want to display a welcome message to the user after he or she logged in, this is how you would go about it. Variables are case sensitive.

<h1>Oh hi {$loggedinuser.firstname}, I didn't see you come in!</h1>

Security

The last example was actually a bad one. Because the 'firstname' is entered by the user itself, we cannot trust the user for supplying a real name. This exposes a so-called XSS security hole. As soon as your user is able to write any form of javascript, they will be able to exploit your site.

To mitigate that, the template engine has a feature to automatically filter the html. You can use this by using the double-dollar-sign format:

<h1>Oh hi {$$loggedinuser.firstname}, I didn't see you come in!</h1>

I can not emphasize enough how important this is!

If you use template variables within javascript, the situation changes this a little bit. Strings that are considered 'safe' in HTML, are not always safe in javascript. The template engine will detect whenever you use variables in a script tag:

<script type="text/javacript"> alert('Oh hi {$$loggedinuser.firstname}, I didn\'t see you come in!'); </script>

When a template engine sees you used a variable within a script tag, it will apply the appropriate encoding for javascript. There are a few important things to note:

  • If you don't supply type="text/javascript", the template engine will not know and you are at risk.
  • The same security considerations apply in event handlers (onclick, onload, etc). Never use template variables there, because the template engine is not aware of the spacial status of the event attributes.
  • Try to avoid using template variables in general if you can, it's bad practice and dangerous. It is intended as a last resort.

Structs

A more recent feature is a struct syntax. In the previous examples 'loggedinuser' is actually a struct. All the items under it (firstname, lastname, email,etc..) are all keys in the structs.

Items in a struct behave slightly different from normal variables. If you try to access a non-existant item within a struct, no error is thrown and the variable is replaced with an empty string. If you do this with a base variable an error is thrown and the page will not load.

Example:

{$$loggedinuser.yourmomsname} // Will display nothing {$$yourmom} // Will throw an error {$$yourmom.firstname} // Will throw an error

GET variables from the query string

It's very easy to use GET variables. To get the value of ?yourVar=1234 simply use:

{$$get.yourvar}

Always use the double-dollar format if you're displaying GET variables.

Defining your own attributes

Every component allows defining arbitrary template variables, which can be used within the actual component.

<fm:IfLoggedIn customVar="customValue"> Oh, hi.. I heard you were logged in. And what's this stuff about {$customVar} </fm:IfLoggedIn>

This is not the best use-case possible, but it can be extremely useful to use in conjunction with fm:Include. The 'customVar' attribute here turns into a template variable that will work within the entire scope of the fm:IfLoggedIn component. This is different from most programming language, because a variable will normally exist (once defined) for the remainder of the codeblock. In this template engine variables can only defined in an outer block, and will only work in an inner block. Template variables are cascading!

While this seemed like a good idea at the time, this unfortunately introduces an odd behaviour in some instances, as illustrated here:

<fm:IfLoggedIn loggedinuser="M.J."> Hi {$loggedinuser.firstname} </fm:IfLoggedIn>

This will throw an error, because loggedinuser is now overwritten. An even weirder scenario is that attributes from a sub-component can be defined by it's parent:

<fm:IfLoggedIn uid="1234"> <fm:MediaList> <fm:Loop> {$$media_title}<br /> </fm:Loop> </fm:IfLoggedIn>

Because we defined the uid variable in fm:IfLoggedIn, it will be used as an attribute in fm:MediaList. If you normally expected to generate a list of all media, you will now only see media from one specific user. Although this is a handy in some situations, this can also be really confusing. All attributes of all components are now dependent on the current variables in scope. This highlights that a template variable = an attribute.

The original intent was to make it easier to generate for example a gallery on a users' profile page. There is no need to specify the uid because it is aware of what page it is in.

This was a design mistake though, because there are situations it can become hard to determine why for example a medialist does not display what you initially thought it would. This especially applies when you are nesting for example a medialist within another medialist. In a future version of the template engine we might solve this, but for now we are stuck with this behaviour. If you encounter a case like this, you can clear existing variables by specifying empty attributes (uid="").