Base Table - FwTableSortable

Ember FW Table was first designed with one sole purpose: to create an easy component to extend Ember Light Table, so that the tables in the apps could be standardized across the board, and also so they could be easier to understand. While there have been a few other more minor things added to the ember-fw-table package, for the most part, it has accomplished that quite admirably. So, the main component that you need to know about is FwTableSortable which is the FW Table written to extend Ember Light Table. You can find the API docs for it here, but because of how common it is in the apps and the fact it is somewhat complex for an individual component, we will point to places you can find information about it here.

Basic Usage

The full documentation for FwTableSortable can be found in our API docs for it, but there are some very basic things which should be mentioned. By default, the table should be called something like this:

<FwTableSortable
    @data={{model}}
    @columns={{columns}}
    @title='Table Title'
    @responsive=true
    @tableActions={{hash
      edit=(action 'edit')
      delete=(action 'delete')
    }}
/>

Properties

For a full list of all the properties that can be used in this component, see our API docs here. It is recommended that you look through all of these to at least familiarize yourself with the different things that this table is able to do. Not everything which is listed in this list will be discussed here, because some of the things are so limited in their use case, they are not needed for a quick introduction to this component (ie resizeOnDrag which allows column resizing, or breakpoints which allows to determine columns on a breakpoint per number rather than per column, etc). What follows is a discussion of the most important attributes.

Columns

Columns is perhaps the most important property, which can often be the most confusing for new developers. It fully extends the Ember Light Table Columns class, without any updates (besides adding a couple of other valid keys to it), so Ember Light Table's columns documentation gives a full list of all valid keys. At its most basic, you will be making an array to pass into the @columns property of the FwTableSortable component, like so:

Javascript File:

/* it is often a good idea to define columns outside the Ember Object to avoid an ember-leaking-state
 error an exception to this is if it is complicated enough to need to be built by a computed
 property */
let columns = [
  {
    label: 'Title',
    valuePath: 'title'
  },
  {
    label: 'Description',
    valuePath: 'desc'
  }
];
export default Controller.extend({
  columns,
  //... the rest of the stuff
});

Handlebars file:

<FwTableSortable @data={{model}} @columns={{columns}} ... />

The complexity with columns is most felt when it comes to seeing the many different keys that are available for use within a column object. A full list of valid keys is not available because there are some keys that we have added to the default Ember Light Table Column keys, which can be seen here. In addition to this, we have added a few keys that are used for the features described below in Special Topics, and they are explained there (some of them use default keys, some of them use new keys). Some of the more important, keys for Columns, which should be especially highlighted are the following:

  • label gives the title of the column. It will either appear in the column header, or if it is in an expanded row (see below for description), it will appear in bold with a colon before the data. See label.
  • valuePath gives the path for the value on the model for what the data for this column should display (not the value itself, but merely the path to the value). For example, if this.get('model.title') will return the desired value within the model you are displaying in the table, the valuePath for the title column should just say title.
  • cellComponent allows you to define a component to have full control over what is rendered within the cell itself. Often these cell components defined by each app can be found in components/cells folder, and are used to do a variety of things. A few pre-defined cell components by Ember FW Table are described, here. For more details on cellComponent itself, see Ember Light Table docs.
  • format is a function which is used to format the data before it is displayed. This is superior to cellComponent for exporting (see below). There are several pre-defined formats by Ember FW Table that are worth checking out, Format Util. For more information on the format key, see here
  • width is a key which simply takes a css size for the default width for the column (usually should be given as a pixel string, such as width: '80px').

There are other column keys (either native to Ember Light Table or created by Ember FW Table) that are very commonly used for one of the new functionalities instituted by FwTableSortable, but these column keys are discussed below in Special Topics.

Note: The only key added by Informatics and not described below is the hideLabel key, which is a boolean. This is for when the times that a label is not desired (at times for the expanded row). This will display the cell without a label, but any formatting must be done through the cellComponent, not through the format key. If label is not set and hideLabel is not true, the cell will simply not appear.

Finally, there are helpful utils which will return a column object for you for common columns used in virtually every table. It is worth checking out for your columns array, it is the Base-Cells Util.

Other Important Properties

Columns are certainly necessary for any table, but it is not the only property that is especially important found in FwTableSortable. Other properties that deserve attention, albeit with less of a description are the following:

  • data is the table row data, which should be an array of objects. Usually an array of models. See more details here.
  • title is the panel title which appears in the header of the table. If HTML is desired, you must use the block format. See more details here.
  • empty is the text to display if the table is empty.
  • responsive is a boolean that allows the table to render differently dependent upon the screensize. This should 99.999% be set to true. If your breakpoints don't appear to be working, it is probably because this repsonsive attribute is not set. See more details here
  • tableActions is a hash of actions, which should be used for your actions cell (or other components). You should name these actions so that they can be easily used. In our example above, there are two actions passed, which can be accessed by the actions cell component as tableActions.edit and tableActions.delete.

For a full list of every property, again, see our API Docs, but the ones listed here should be the most important ones to get you started.

Special Topics

The main use of FwTableSortable is actually a few features that are added to Ember Light Table, which make FwTableSortable superior for our usage at Informatics. These are: Sorting, Expanded Rows, and Exporting. The idea was to make a consistent and easy way to integrate these features into Ember Light Table. Since these features are not documented anywhere else, we will give them a bit more focus than the base component.

Sorting

By default, all tables are sortable, meaning you can click the title to sort by the column. Columns are several keys used in sorting, which can be passed into each column object in your column array:

  • sortable: If true (default), this column is able to be sorted
  • valuePath: This key is used by Ember Light Table to determine data to display in the cell, and is also used by default as the key to sort by
  • sortKey: If the column has no valuePath or otherwise sorts using a different key than is displayed, set this key to the name of the key to sort by. An example use is a column that displays a money value, which might be formatted with a dollar sign to display in valuePath, but to sort you want the number type.

In addition, the FwSortableTable component itself has several properties that can be set to control sorting:

  • defaultSort: This determines the key(s) to sort by when the table is initially loaded. It can either be a string or an array of strings. Additionally, when two values are equal in the sort key, this is used as a fallback.
    • onSort: Action passed in that is called before adjusting the sort key. This is not required to make the table sort, only if you want additional behavior. An example use is in a paginated table to refetch the table rows based on the new sort order.

FW Table Sortable uses Ember's computed macro to handle sorting, meaning the keys used in sorting must be natively sortable by Ember. This supports a variety of types including strings, numbers, booleans, and JavaScript date objects. It does not support moment objects, but as a work around you can set the sort key to the moment object’s internal date object _d. For example, if the value path is "date", sortKey will be "date._d".

Expanded Rows

Since many of the tables used in the FW apps have more columns than can easily be viewed on typical devices, the tables have the ability to show hidden columns within an expanded row. This is used both for columns which require a full width and for columns hidden by responsive behavior (such as being on a mobile device).

Expanded rows are simply columns within the table’s column array. By default, if the column is not shown among the main table, it will show in the expanded row if

  • The column has no value path (ie you are using cellComponent)
  • The value of the row matching valuePath is not empty.

The behavior of columns can be modified using the following properties in the column object:

  • breakpoints: Array of breakpoints to show this column. If the screensize is not within these breakpoints, this column will display in the expanded rows. See also breakpoints. Ember FW Table, by default adds four breakpoints: mobile, tablet, desktop, and jumbo.
  • hidden: If true, the column will always display as an expanded row
  • showExpanded: If set, this overrides the default behavior of the expanded row showing if valuePath is not empty. This has two modes based on the type of the property:
    • Boolean: If true, the column always shows as an expanded row when not a column (hidden or breakpoints). If false it never shows as an expanded row.
    • String: If the value of the row matching this key is truthy, this column will show as an expanded row

When viewed as an expanded row, the column will still show its cellComponent as normal if used. Otherwise, the normal value from format will be used, falling back to the raw value. The property isExpandedRow will be set to true when calling the cell component, allowing distinguishing expanded row view from a normal column cell.

Exporting

By default, a table will not be exportable. To make it exportable, set the canExport component property.

Exporting is handled through the table columns, meaning each table column becomes a column in the csv file. By default, exporting ignores the cellComponent property, meaning any display logic should be done using a computed property on the row or a formatted function to be compatible with exporting.

To better control exporting, the following properties can be set:

  • format: The format function which is used to adjust the value for display in the table is called on export. The property export is set to true in the functions context, meaning calling this.get('export') will return true if exporting and false if a normal cell.
  • canExport: If true (default), this column can be exported. Set to false to skip this column on exporting, typically used on columns such as row toggles or action buttons.
  • exportOnly: If true, the column will not show in the table at all. This is used when a single table column needs to be exported as multiple columns.

If desired, the export logic can be called outside of a FW Table Sortable component. This is used to have an external export button, or to have a full results export in paginated results. See the export util for more information.

Block Format

Most of the time, when you are using FwTableSortable you will simply use the parameter call. There are times however, when you will need to override the header or the footer of the table with HTML. If you need a more complicated header or footer for this reason, there is a way to use block format. In summary, the reasons you may desire to use block form would be:

  • You need more complicated HTML in the header than just an export button (ie more buttons, or even showing a Font Awesome Icon in the header)
  • You desire to show a footer and/or header on your table

In block format, you need to manually setup your export button (if you also desire exporting), as it will not be automatically added for you. The first parameter passed to you in the block yield is export, which contains the export action.

Additionally, if you want to set up the block to have a footer as well (in case the model is a modal) you will need to use the showHeader and showFooter booleans. By default, showHeader is true and showFooter is false. When one is true and one is false, the block data is used for the one that is true. So by default all of the data in the block will be put in the header. If showHeader is set to false, and showFooter is set to true, all of the data in the block will be put into the footer. Sometimes, however, you will want to render content in both the header AND the footer, and in this case, you will need to use the second parameter, header which will be a boolean. This boolean will be true when in the header, and false when in the footer.

Note: if showHeader is false, and there is a block for showFooter, the header will still be rendered as normal (using canExport and title, etc).

So then, to put everything together about block format, here is an example of how you would format it:

<FwTableSortable
    @data={{model}}
    @columns={{columns}}
    @canExport=true
    @responsive=true
    @showFooter=true
    as |export header|
>
    {{#if header}}
        {{!-- content here which will appear in the header, keep in mind you will need to manually
          use export action as shown --}}
        <strong class="panel-title">My New Panel Title</strong>
        {{! other HTML to render}}
        <button class="btn btn-xs btn-primary pull-right" {{action export}}>
            <i class="fa-regular fa-file-excel"></i>
            Export
        </button>
    {{else}}
        {{!-- content here which will appear in the footer. Most often close button--}}
        <button class="btn btn-sm btn-danger pull-right" {{action "closeModal"}}>
            <i class="fa-solid fa-xmark"></i>
            Close
        </button>
    {{/if}}
</FwTableSortable>