OverviewThe datatable component displays tabular information in a spreadsheet like fashion and supports re-sizable columns, scrolling, sort, pagination and more... Its look an feel is similar to the datatable YUI component to which it borrows its CSS but its implementation is mostly based on XForms rather than JavaScript.Using a datatable component is very similar to embedding an xforms:repeat control within an (X)HTML table. It's basically just a matter of replacing the xhtml:table element by the fr:datatable bound element and adding a few attributes to control the features of the datatable. The table displayed above can be defined as:<fr:datatable scrollable="both" width="800px" height="500px"> <thead> <tr> <th fr:sortable="true" fr:resizeable="true">Date</th> <th fr:sortable="true" fr:resizeable="true">Author</th> <th fr:sortable="true" fr:resizeable="true">Title</th> </tr> </thead> <tbody> <xforms:repeat ref="/atom:feed/atom:entry"> <tr> <td> <xf:output ref="atom:published" xxforms:format="format-dateTime (., '[M01]/[D01]/[Y] - [h01]:[m01]:[s01]')"/> </td> <td> <a href="{atom:author/atom:uri}"> <xf:output value="atom:author/atom:name"/> </a> </td> <td> <xf:output value="atom:title"/> </td> </tr> </xforms:repeat> </tbody></fr:datatable>Attributes
|
| Events dispatched by the datatable | fr-selection-changed | This event is dispatched when the selected node changes for whatever reason (initialization,
click, xforms:setindex, repeat nodeset update, sort order and page
update, ...). The following contexts are sent by this event:
oxf:sort() function and that its parents and
siblings may not be the same than in the original datatable repeat
nodeset. |
fr-goto-page | This event is dispatched with both external and internal paging when users switch to another page:
fr-new-page context. | |
fr-update-sort | Dispatched when the sort is handled externally to the datatable and the sort order
needs to be updated. The value of the column index where the user has
clicked is passed as the fr-column context. | |
| Event you can dispatch to the datatable | fr-goto-page | With internal paging (i.e. when paging is handled by the datatable for
you), you can instruct the datatable to switch to a given page by
sending it this event. When dispatching the event, set the fr-new-page property to page number you'd like to go to. For instance:<xforms:dispatch ev:event="DOMActivate" <xxforms:context name="fr-new-page" select="2"/></xforms:dispatch> |
Simplifications
The component supports two syntactical simplifications or abbreviations.xforms:repeat/xhtml:trcan be replaced by xhtml:tr/@repeat-ref [SINCE 2012-04-06] (or for backward compatibilityxhtml:tr/@repeat-nodeset). The fragment:
<xforms:repeat ref="/atom:feed/atom:entry"> <xhtml:tr> ... </xhtml:tr></xforms:repeat>Can be written:
<xhtml:tr repeat-ref="/atom:feed/atom:entry"> ...</xhtml:tr>- Headers can be generated from cells labels.
It is very common that columns consist of a single
This is more compact and arguably easier to read than the original form because the definition of each column is grouped together instead of being split between the body and the header.
<xforms:output> control. In that case, it can be considered simpler to provide an <xforms:label> rather than explicitly define table headers. Our example could be written:<fr:datatable scrollable="both" width="800px" height="500px"> <tbody> <tr repeat-ref="/atom:feed/atom:entry"> <td fr:sortable="true" fr:resizeable="true"> <xf:output ref="atom:published" xxforms:format="format-dateTime
(., '[M01]/[D01]/[Y] - [h01]:[m01]:[s01]')"> <xf:label>Date</xf:label> </xf:output> </td> <td fr:sortable="true" fr:resizeable="true"> <a href="{atom:author/atom:uri}"> <xf:output value="atom:author/atom:name"> <xf:label>Author</xf:label> </xf:output> </a> </td> <td fr:sortable="true" fr:resizeable="true"> <xf:output value="atom:title"> <xf:label>Title</xf:label> </xf:output> </td> </tr> </tbody> </fr:datatable>This is more compact and arguably easier to read than the original form because the definition of each column is grouped together instead of being split between the body and the header.
Restrictions
The datatable component has been designed to look like the syntax of an
ordinary (X)HTML table and will usually behave as expected. That being
said, under the cover, the component needs to analyze the table
structure and to implement features such as sort and pagination it has
to rewrite the ref expression of the main xforms:repeat with pieces
of XPath expressions cut from XForms controls fetched from table cells.This is a fairly complex task that is implemented in XBL and XSLT and that imposes several constraints to the structure of the datatable and the XPath expressions that can be used. As a result, the datatable imposes the following restrictions on the table structure after the simplifications have been processed:
- The content of the header and body rows must be composed of
xhtml:th(for the header) andxhtml:td(for the body) elements and ofxforms:repeatelements enclosingxhtml:thorxhtml:tdelements. No other elements are supported. For instance, you cannot have anxforms:grouparoundxhtml:thorxhtml:td. - The
xforms:repeatcan be freely mixed withxhtml:th(in header) andxhtml:td(in body) elements but there should be an exact and immediate match between the structure of the table body and headers. - The number of columns should be the same in header and body rows.
- There must be exactly one header row in the table header and no other content.
- There must be exactly one
xforms:repeatembedded in the table body and no other content.
Other important restrictions are dictated by the XPath "cut and paste" algorithm involved when the datatable supports sort and pagination internally. These restrictions can be summarized by the fact that the expressions used in XForms controls that will be used as sort keys must be valid in an element that is external to the xforms:repeat where they appear. The main effect of this issue is that they cannot use local variables (see issue #314323).
Sort and paginations are implemented in XForms by rewriting the
Loading indicator
The datatable is good candidate on which to apply the delay expensive submissions tuning technique. The datatable offers a way for you to indicate that the data is being loaded using the optional loading attribute. The value of this attribute is an XPath expression, and its result is interpreted as a boolean value. Typically, you will:
The datatable CSS uses the class
Properties
Browsers can take a noticeable amount of time to render datatables, up to seconds for larger tables on slower browsers. By default, datatables are rendered as soon as they are potentially visible (relevant, not in a non-current case, or a non-displayed dialog). If you set the following property to
Sort and paginations are implemented in XForms by rewriting the
<xforms:repeat> nodeset expression. This means that context functions such as index() or position() are evaluated in the context of the sorted and paginated node set.Loading indicator
The datatable is good candidate on which to apply the delay expensive submissions tuning technique. The datatable offers a way for you to indicate that the data is being loaded using the optional loading attribute. The value of this attribute is an XPath expression, and its result is interpreted as a boolean value. Typically, you will:- Use a node in an instance (say
<loading>) a way to keep track of whether the data is being loaded or has already been loaded. You initially storetruein that node (e.g.<loading>true</loading>). - You make your datatable point to that node (e.g.
<fr:datatable loading="/path/to/loading = 'true'"/>). - You delay the expensive submission until after the form is loaded.
- When the submission is done, you set the content of the node to
false.
The datatable CSS uses the class
fr-datatable-is-loading to set a background image (in this case a spinning icon) for the central area of the datatable. You can change this by overriding in your CSS the default style defined for the fr-datatable-is-loading.Properties
Browsers can take a noticeable amount of time to render datatables, up to seconds for larger tables on slower browsers. By default, datatables are rendered as soon as they are potentially visible (relevant, not in a non-current case, or a non-displayed dialog). If you set the following property to true (its default is false), datatables rendering is delayed until they become at least partially visible on the screen.<property as="xs:boolean" name="oxf.xforms.xbl.fr.datatable.init-in-viewport" value="true"/>In cases where users have to scroll to reach datatables, you may improve the user experience by delay the rendering until users reach the datatables while scrolling. This can make a significant difference in cases where you have several datatables on the page: instead of introducing a longer initial wait time, users will experience shorter wait times as they scroll down and reach each datatable.
Displaying a row number in internal mode
In some cases, you want to show, maybe in the first column, the current row number. This row number needs to take paging and sorting into account. For instance, if you have 4 items per page and you are on the second page, whatever the sorting is, you'd like the lines to be numbered 5, 6, 7, and 8, as in this screenshot:
For this, you need two constructs:
position() tells you the current line on the current page, and $fr-dt-page tells you the page number. Based on those two constructs, inside your <xhtml:tbody> add a column:<xhtml:td> <xforms:output value="position() + ($fr-dt-page - 1)*4"/></xhtml:td>And obviously, you'll want to add a corresponding
<xhtml:th/> inside your <xhtml:thead> to keep the number of columns in your table headers in sync with the table body.See also
- Datatable new and old generations
- XBL Component - Datatable Implementation Notes (currently slightly out dated)
- XForms sandbox samples named
datatable-ng*




