Data Renderers
Styling can be applied to DataFrames using Data Stylers. However, there are times when you want to render data differently rather than just changing the styling. Here are some use cases.
- A single card layout instead of a row layout where multiple fields are all organized in a free-format.
- Visual representation of data such as showing stars for the ratings field.
- Concatenate multiple fields in a single cell.
Some of the above use cases can be solved using calculated fields although that is unnecessary if the calculation is only required for data presentation.
Data rendering is accomplished using templates. SQL Frames uses Eta to create and evaluate the templates.
Row renderer
Here the requirement is to render the entire row as a custom block with important information for the user.
This is done using the df.fmt.setRowRendererProvider()
API.
Let's go through the key API elements. The template itself is created using df.fmt.tt
tag API provided by
the df.fmt
formatting plugin. The content of the template can be any valid HTML which can access the current
row data using two variables it.v
and it.dv
. it.v
provides access to the raw values while it.dv
provides
access to the display values which are generated by applying formatting such as localization to the raw value.
If the field name is a valid javascript variable name, then it can be directly specified using the dot notation
such as it.dv.Region
. But if it is not a valid javascript variable name, then the indexing notation has to be
used such as it.dv["Item Type"]
.
The values accessed using it.dv
are sanitized to prevent xss attacks. The values accessed using it.v
are
raw values that are not sanitized. They are expected to be used within the template only for any sort of calculations
and never to directly render them.
Even though the data is not rendered as a regular table-row the markup still uses table and table rows ensuring the infinite scrolling with virtual table rendering is still available with data renderers.
pdf.fmt.setRowRendererProvider
is the API used to specify the row renderers. The getRenderers
API
returns an array of 1 or more row renderers. This allows the same data row to be rendered as multiple
rows in the presentation layer.
Toggling of dark mode can be supported by defining style sheet with css variables that change based on
html[data-theme='dark'] or using the it.darkMode
boolean and conditionally changing the style inline
as shown above.
With event handling
The template provided for rendering can contain javascript code. Below example shows how a link is provided with a javascript event handler.
As mentioned above, only the display values are sanitized for xss attack but not the template. This is because, the developer writing the template or the end user using the template is expected to trust the code but not the data they are working with.
Row and Row Renderer
It is possible to render the regular row along with row renderer. This is possible using pdf.fmt.defaultRowRenderer
which is a special row renderer giving the default behavior.
When both the row and renderer are displayed, the up/down arrow key navigation will only work on the first column (since the renderer row contains a single column spanning the entire row).
Hierarchical Row Rendering
SQL Frames allows making any DataFrame into a hierarchical DataFrame. These hierarchical data frames by default are rendered as a hierarchical grid. However, an alternative presentation of grouped lists like in Numbers on Mac can be created using row renderers as shown below.
Cell Renderer
Cell renderers have access to the data from the entire row. Hence, they can augment the cell details
with other details from the row. In the following example, the Country
cell is augmented with the Region
it belongs to.
df.fmt.setFieldRenderer
API is used to set the field renderer for a field. A field can have only one cell
renderer.