Writing your own PocketQuery Templates
PocketQuery Templates help you visualize results of your Queries. When you execute a Query, the result from the Datasource is passed through a Converter (Writing your own PocketQuery Converters), and then the result from the Converter is passed to a Template.
For the most basic use cases there is a default Template which displays your result in a simple table. However, if you have a complicated Query with a structured result, or you just want to add some fancy visualization/effects, the basic Template might not be enough. Thus, in this tutorial, we will look more closely at PocketQuery Templates. You can find the following here:
Apache Velocity Templates
If you are interested in technical details of Apache Velocity Templates, you can refer to the official resource. In this page, we will focus solely how they are used in the context of PocketQuery.
A Velocity Template (VT) is a template written in the the Velocity Template Language (VTL). Which is commonly used to generate HTML. It lets you define and use variables, which are marked with $
, and you can also include simple logic (such as foreach
, if-else
, and more). The templating engine is written in Java. Consequently, you can see many similarities with the Java programming language; e.g., Velocity template variables are Java objects. You can access their attributes using the .
notation. For example, let’s consider an instance cat
of the following class:
public class Cat {
public String name;
public String makeNoise() {
return "Meooow!";
}
}
$cat.name
prints its field “name”.$cat.makeNoise()
calls its method “makeNoise” and prints “Meooow!”.
In the following sections, we will look at some simple PocketQuery templates and explain their syntax/semantics. If you are not familiar with HTML, we recommend to start with an HTML tutorial (for example, W3 School tutorials) to understand the basic concepts of this markup language. If you don’t have any experiences with Java, don’t worry, it is not an essential prerequisite.
1. Getting started: accessing the Query result and setting variables
Let’s start with a basic scenario. Consider the following result passed from your Converter:
{
name: "Lively Apps",
fullName: "Lively Apps GmbH",
founded: 2020
}
We can create a simple Template displaying this object:
<p>Our company is $result.name.</p>
<p>It was founded in $result.founded.</p>
The result displayed after macro execution is:
Our company is Lively Apps.
It was founded in 2020.
Explanation: Your Converter result is accessible through the $result
object. We want to access the fields “name” and “founded”. Thus, we use the dot notation to access these fields: $result.name
, $result.founded
.
We might want to show the same value multiple times, such as:
<p>Greetings from $result.name!<p>
<p>We are $result.name from Germany.<p>
This Template is working fine but we can make it more readable by introducing a variable. You can do that using the #set
directive, for example #set($companyName = $result.name)
. This creates a new variable, called “companyName”, with its value being assigned to $result.name
(in our case, the result is “Lively Apps”). Keep in mind that the $
before the name of the variable is essential and you have to use it for any variable name. The Template can then be changed to:
#set($companyName = $result.name)
<p>Greetings from $companyName!<p>
<p>We are $companyName from Germany.<p>
Both these Templates have the same result, which is:
Greeting from Lively Apps!
We are Lively Apps from Germany.
You can also use this command to change the value of an existing variable, for example:
#set($companyName = $result.name)
<p>Greetings from $companyName!</p>
#set($companyName = "Lively Apps 2")
<p>We are $companyName from Germany.</p>
The result is now:
Greeting from Lively Apps!
We are Lively Apps 2 from Germany.
2. Introducing validation and conditions: if/else blocks, basic operators
Sometimes, your results might have parameters that do not necessarily contain any value (if this is the case, such a value is called null
or undefined
). Let’s consider the following object returned from our Converter:
{
name: "Lively Apps",
fullName: "Lively Apps GmbH",
country: null,
founded: 2020
}
We want to create a Template, which optionally (i.e. only when the value is present) displays parameter “country”. To reach this behavior, we can use an if-else
construct. Its syntax is:
#if (CONDITION)
EXECUTED WHEN CONDITION == TRUE
#else
EXECUTED WHEN CONDITION == FALSE
#end
In our case, such a template might look like the following:
#if ($result.country)
<p>We are from $country.</p>
#else
<p>We won't tell you where we are from.</p>
#end
In our case, where the “country” is null
, the second block will be executed, therefore, the result is:
We won't tell where we are from.
Let’s consider the opposite scenario, where the “country” is set to some value, for example country: "Germany"
. In that case, the first block would be executed and the result would be:
We are from Germany.
3. Accessing structured results: arrays, maps, loops
In the most of cases, your Query result is an array of elements, e.g.:
[
{id: 1, name: "Scandio", country: "Germany"},
{id: 2, name: "Lively Apps", country: "Germany"}
]
There are two options, how you can access these elements. To demonstrate it, let’s consider two scenarios:
We want to obtain one element; the first one, it does not matter how many elements were returned in the array.
We want to obtain all elements and perform some action with all of them.
In the first scenario, we can use direct access to obtain the element. We can do that using $result.get(index)
, where index stands for the position of the element in the array. When using this approach, keep in mind to check the size of your array. If you try to access an element that is not in the array, the execution fails with an IndexOutOfBoundsException. Example Template code could look like the following:
#if ($result.size() >= 2)
#set ($firstElement = $result.get(0))
#set ($secondElement = $result.get(1))
<p>The first item is $firstElement.name and the second is $secondElement.name.</p>
#else
<p>Not enought results :-(...</p>
#end
For our input, the result of this template would be:
The first item is Scandio and the second is Lively Apps.
Sometimes, we are not interested in the exact number or order of our elements but simply want to print all of them. To do so, we can use a loop. In our case, we can use foreach
loop to access all elements in the array, one by one. Such a construct has the following format:
#foreach (ELEMENT in ARRAY)
CODE THAT IS EXECUTED FOR EACH ELEMENT IN THE ARRAY
#end
In our case, we can do the following:
#foreach ($element in $result)
<p>ID: $element.id, name: $element.name</p>
#end
The result is then:
ID: 1, name: Scandio
ID: 2, name: Lively Apps
In some cases, we may want to iterate over an object’s properties rather than the elements in an array. To do so, we can use the same constructs, with a little modification. Let’s consider a situation, where we don’t exactly know which parameters our results have, and we want to print all of them. This can be achieved by introducing another (nested) loop.
Loops iterating over properties are a bit different. They have the following structure:
#foreach ($entry in $object.entrySet())
#end
When you create an entry set from an object, you simply convert its properties to an array. For example, consider object:
{
id: 2,
name: "Lively Apps",
country: "Germany"
}
The .entrySet()
method converts it to:
[
{key: "id", value: 2},
{key: "name", value: "Lively Apps"},
{key: "country", value: "Germany"}
]
Thus, a loop over our entries has 3 iterations, one for each property.
Let’s demonstrate it with the following example, so we can visualize what we mean by the “nested loop”:
#set ($counter = 1)
#foreach ($element in $result)
<p>$counter:</p>
#foreach ($property in $element.entrySet())
<p>$property.key - $property.value</p>
#end
#set ($counter = $counter + 1)
#end
Let’s go through this example line by line:
We set the variable “counter” to “1”, so we are able to print the index of the element that is processed.
We loop over all elements in the “result” array.
We started element processing, so we print the “counter” variable.
We loop over all properties for the current element from “result” array.
We print the property name (
$property.key
) and property value ($property.value
).We increment “counter”.
end
does not have any logical meaning, it marks the end of the loop.
The result of execution for our example is:
1:
id - 1
name - Scandio
country - Germany
2:
id - 2
name - Lively Apps
country - Germany
The template above can be simplified. Apache velocity offers a variable $velocityCount
(documentation), which is natively present in each loop. It starts at 1 and automatically increments each iteration. This piece of code generates the same output:
#foreach ($element in $result)
<p>$velocityCount:</p>
#foreach ($property in $element.entrySet())
<p>$property.key - $property.value</p>
#end
#end
Alternatively, you can iterate only keys or only values of element properties using .keySet()
and .values()
. In our scenario, we can obtain all values (alternatively all keys) using:
#foreach ($value in $result.values())
<p>$value</p>
#end
Or for all keys:
#foreach ($key in $result.keySet())
<p>$key</p>
#end
Which results in the following (when using .values()
):
id
name
country
Or eventually (when using .keySet()
):
2
Lively Apps
Germany
4. PocketQuery helpers
In a real use case scenario, you might need to visualize some complex values. By “complex values” we can understand for example dates, currencies, percentages, etc. Maybe you also want to perform some operations over results, such as sorting, making elements unique, or reversing the order of elements. PocketQuery introduces a set of helpers, which will help you format the values:
On this page, you can also find helpers that can be used to execute nested queries (i.e., you can execute another query inside a template) or nested templates (i.e., you can render another template inside a template).
5. Default PocketQuery Template explanation
If you don’t choose differently, your Queries always use the default PocketQuery Template. It looks as follows:
#set($tableRows = $PQ.toList($result))
#set($tableHeaders = $tableRows.get(0).keySet())
<table class="aui">
<thead>
<tr>
#foreach ($header in $tableHeaders)
<th>$!header</th>
#end
</tr>
</thead>
<tbody>
#foreach ($row in $tableRows)
<tr>
#foreach ($column in $row)
<td>$!column</td>
#end
</tr>
#end
</tbody>
</table>
Explanation: On the first line, we obtain the query results and flatten them (using $PQ.toList helper). On the second line, we obtain header columns by looking at the first element in the result array and obtaining its keys only (more detailed description of .keySet()
is in the loops section). Then we construct a table header (starting on line 4) by iterating through parameter keys and printing them. Note that we used the $!
sign, it denotes that the $header
variable is printed only in the case where it is not null
/undefined
. From line 11, we print the table body. We iterate over all elements in the results array and print their values (in case it is present).
Even though the Velocity Templating Language is immensely powerful, it is always a good idea to first bring your Query result into shape using a Converter. Converters are written in an actual programming language (JavaScript) and are therefore much easier to use for performing complex operations on data. If you want to learn more, continue with: Writing your own PocketQuery Converters.
Build your own Template
In this page, we described basics of Apache Velocity Templates and how we can use them to present PocketQuery results. Now you can apply what you’ve learned and polish your query results to perfection. Do you have any questions? Issues? Feedback? Don’t hesitate to contact our support!