Fragment Configuration in the View

Now we want to support another config parameter, i.e. allowing the user to specify which properties of the encounter are displayed in columns. Through a particular Groovy trick, we can do this purely in the fragment's view.

Let's change the way we include the fragment in helloWorld.gsp as follows:

${ ui.includeFragment("yourmoduleid","encountersToday", [ start: "2011-02-16", end: "2011-02-16 23:59:59.999", properties: ["location", "datetime"] ]) }

(The fragment config is now a Map that also includes a List as a value.)

To implement this functionality, we change the the encountersToday.gsp page as follows:

<% def props = config.properties ?: ["type", "datetime", "location", "provider"] %> <table> <tr> <% props.each { %> <th>${ ui.message("Encounter." + it) }</th> <% } %> </tr> <% if (encounters) { %> <% encounters.each { enc -> %> <tr> <% props.each { prop -> %> <td><%= ui.format(enc."${prop}") %></td> <% } %> </tr> <% } %> <% } else { %> <tr> <td colspan="4">${ ui.message("general.none") }</td> </tr> <% } %> </table>

We've introduced a few new tricks here. First, the easy ones:

  • the UI Framework exposes the FragmentConfiguration as "config" in the view (so the "properties" that we specified while including the fragment are accessible from the fragment view as config.properties)

  • Groovy allows loosely-typed variables. Saying "def x = 5" is approximately like saying "Object x = 5" in Java, but in Groovy it's actually considered good style.

  • Groovy adds a new operator ?: (also called the Elvis operator--look at the hair) which returns the first argument if it is not null, and the second otherwise. So "a ?: b" is equivalent to "a != null ? a : b".

So the first line of code sets the variable "props" to be equal to the "properties" property of the FragmentConfiguration if specified, or our original property list if you don't specify one explicitly. You should use this idiom a lot.

I previously said you can think of a closure as an anonymous function whose parameter is called "it". You may actually specify the parameter name a closure takes with the syntax:

{ paramName -> code body }

In our code we now have a closure that contains another closure, so we explicitly specify parameter names of "enc" and "prop" to make it clear what we are doing.

We use one final advanced Groovy trick, which is that:

  • object."property" is equivalent to object.property

  • Groovy strings let you insert values, e.g. "${ prop }" is basically the same as prop.toString().

  • Therefore enc."${prop}" means to look up the prop property (interpreted dynamically) of the enc object.

  • we also had to use less-than-percent-equals notation to allow that value to contain a dollar-curly-brace expression.

This trick makes the code quite confusing to read unless you know what it's doing, so make sure you have good variable names, indentation, and spacing if you use this. (In fact we should create a reusable fragment "table" that encapsulates this dynamic-property code in one place, allowing other code to get this behavior without the complexity.)