Actions

Custom actions can be applied to 4 areas of an object-table: rows, cells, columns and the object-table itself.

Empty action

In the event that a table contains no rows, an <empty-action> node can be used to add additional UI functionality.

<object-table ...>
    <empty-action icon="fa-angle-right" on-press="$:noResultsAction()" validate="false" />
    ...
</object-table>
function noResultsAction(object){
    // Do something with the object
    console.log(JSON.stringify(object));
}

Note: This works in addition to the empty-message attribute that is available on an object-table.

Row actions

Similar to bind, a row can trigger an action by nesting a standard action tag in an object-table. For example:

<object-table ...>
    <action icon="fa-angle-right" on-press="$:rowAction($selection)" validate="false" />
    ...
</object-table>
function rowAction(object){
    // Do something with the object
    console.log(JSON.stringify(object));
}

Tip: It is good practice to place actions at the top of an object-table

When using a function to specify the icon attribute on <action/>, it has access to $object (note: not $selection), for example:

<object-table ...>
    <action icon="$:getIcon($object)" .../>
    ...
</object-table>

Cell actions

When an action is specified within a column, the action will fire when the particular column is selected. The icon, in this case, is placed on the right - and should not be confused with a standard cell icon, which is independent of the action icon.

<object-table ...>
    <column display="{name}" heading="Name">
        <action icon="fa-angle-right" on-press="$:cellAction($selection)"/>
    </column>
    <column display="{surname}" heading="Surname">
        <action icon="fa-angle-right" on-press="$:cellAction($selection)" />
    </column>
    ...
</object-table>
function cellAction(object){
    // Do something with the object
    console.log(JSON.stringify(object));
}

Much like a row action, this function also has access to $selection.

Combining row and cell actions

In the case where both a row and cell action are present, the cell action will take precedence and prevent the row action from firing.

<object-table ...>
    <action icon="fa-angle-right" on-press="$:rowAction($selection)" />

    <!-- Clicking here will fire the row action -->
    <column heading="Name">{name}</column>

    <!-- Clicking here will fire the cell action only -->
    <column heading="Surname" display="{surname}">
        <action icon="fa-angle-right" on-press="$:cellAction($selection)" />
    </column>
</object-table>

Column actions

A column action is displayed next to the column heading, in the same place the filter icon would normally be. If the action is specified, the header-action icon is used regardless if filters are enabled or not.

<object-table ...>
    <column heading="Name">
        <header-action icon="fa-angle-right" on-press="$:headerAction()" />
    </column>
</object-table>

Note: Unlike row and cell actions, this function does not have access to $selection, as they are only rendered once per column.

Common patterns

Header actions can be used in interesting patterns, as follows:

Combo menu

In this example the header action displays a dropdown menu with a set of options, where and when pressed.

function headerAction(){
    var option = actionSheet(["Setting 1", "Setting 2", "toggle-filter"]);
    // do something with the option
}

Combo menu with original filter capability

function headerAction(){
    var option = actionSheet([
        "Setting 1",
        "Setting 2",
        "Toggle Filter" // <--- we want this menu item to have the original toggle-filter capability
     ]);

     if(option === 2){
         // so we specifically return 'show-filter' here
         // this is referred to as a 'return directive'
         return "show-filter"
      }
}

Pin frozen column

In this example, when the action is pressed, a view variable is set which indicates that the particular column should 'freeze' to the left.

<var name="frozen_column" type="string" />

<object-table ...>
    <column freeze="$:view.frozen_column === 'name'?'left':'none'" heading="Name">
      <header-action icon="fa-pin" on-press="$:headerAction()" />
    </column>
    ...
</object-table>
function headerAction(){
    view.frozen_column = "name";
}

object-table actions

Version compatibility

object-table actions were introduced in version 4.34.6 of the JourneyApps Container.

object-table actions enable additional buttons to be appended to the controls area of an object-table. Additionally, these buttons can call functions passing the current data in the object-table.

For example:

<object-table label="Employees" limit="17" empty-message="Your items will appear here" query="employees" mode="paginate">
    <column heading="Name">{name}</column>
    <button-group>
        <button icon="fa-envelope" label="Email" on-press="exportCSV($filteredData, filteredDisplayData, controls)"/>
        <button icon="fa-download" label="Export CSV" on-press="exportCSV($filteredData, filteredDisplayData, controls)"/>
    </button-group>
</object-table>

Each of the buttons call a function in their on-press attribute with the following three parameters:

  1. $filteredData: An object of the form {columns: string[], rows: DatabaseObject[]}. DatabaseObject refers to the familiar JourneyApps object that can be used to update values in the database.

  2. filteredDisplayData: An object of the form {columns: string[], rows: string[][]}. The rows correspond to the text currently displayed in the table. This object can be directly passed to CSV's stringify() function to create a CSV export of the table's data.

  3. controls: An object of the form {page: number, totalPages: number, limit: number, filters: {string: string[]}}. This represents the current state of the search criteria and filters applied to the object-table.

In both parameters where data is passed to the function the sort order and current table filters are applied to the data.

Tip: When you have more than one button in the button-group and would like to emphasize one of them, use mode="split". This will display the first button in the group and place the rest in an actionSheet.

Example: Select all items on a page

main.view.xml
<object-table label="Select one to view details" query="tickets" empty-message="Your items will appear here" limit="5">
    <column heading="Date">{date}</column>
    <column filter="true" heading="Customer">{customer}</column>
    <column filter="true" heading="Pad">{pad_name}</column>
    <column style-align="right" heading="Total">{$object.ticket_total}</column>
        
    <button-group>
        <button label="Select all" icon="fa-check" on-press="$:selectAll($filteredData, controls)" validate="false" style="outline" />
    </button-group>
</object-table>
main.js
function selectAll(filteredData, controls) {
    var startIndex = (controls.page - 1) * controls.limit;
    var endIndex = controls.limit * controls.page;
    // slice the current visible page's objects out of the array of all objects currently rendered (sorting and filtering included)
    var selectedObjects = filteredData.rows.slice(startIndex, endIndex);
}

$filteredData contains an array of all the DB objects currently rendered in the table across all pages. In the above example we โ€˜sliceโ€™ out the specific page that we are interested in - in this case it's the current page which is store in the controls parameter.

Example: One-click CSV export

schema.xml
<model name="employee" label="Employee">
    <field name="name" label="Name" type="text:name" />
    <display>{name}</display>
</model>
main.view.xml
<view title="CSV Export">
    <var name="employees" type="query:employee" />
    <object-table label="Employees" query="employees">
        <column heading="Name">{name}</column>
        <button-group>
            <button icon="fa-download" label="Export CSV" on-press="exportCSV($filteredData, filteredDisplayData, controls)"/>
        </button-group>
    </object-table>
</view>
main.js
function exportCSV(filteredData, filteredDisplayData, controls) {
    var data = CSV.stringify(filteredDisplayData);
    journey.files.saveFile(data, 'data.csv');
}

Last updated