Rows
A row is one entry of a row model: your original datum plus the id, depth, and grouping information the pipeline gave it. This page is the port of TanStack's Rows guide.
Row row is an opaque type. In TanStack a row is an object with properties
and methods (row.id, row.original, row.getValue(...)); here you read it
through functions that take the row as their last data argument. The type
parameter is your own record type, so Row Person is a row over a Person.
Where to get rows from
Table.findRow
To get one row by its id, use
Table.findRow. It is TanStack's
table.getRow, and it returns a Maybe rather than throwing:
lookupRow : Table.State -> String -> Maybe (Table.Row Person)
lookupRow state wanted =
Table.findRow (Table.rowsFromList config state people) wanted
findRow takes the row model, not the config, because ids only exist once
rows have been built. It reads rowsById.
Row models
The pipeline builds the rows and hands them back in three shapes:
model.rows (the tree), model.flatRows (everything flattened), and
model.rowsById. The Row Models guide covers the
stages; these are the two common ways to reach the rows.
Render rows
Render from Table.rowsInDisplayOrder
rather than model.rows directly. It is the page in the order you draw it,
with expanded descendants inserted when Config.paginateExpandedRows is off.
displayRows : Table.State -> List (Table.Row Person)
displayRows state =
Table.rowsInDisplayOrder config state (Table.rowsFromList config state people)
Get selected rows
Table.selectedRowModel filters
any stage's row model down to the selected rows. See
Row Selection.
Row objects
Every reader is a function of the row. Nothing needs the table.
| TanStack | elm-table |
|---|---|
row.id |
rowId |
row.index |
rowIndex |
row.depth |
rowDepth |
row.original |
rowOriginal |
row.subRows |
rowSubRows |
row.parentId |
rowParentId |
row.originalSubRows |
rowOriginalSubRows |
row.groupingColumnId |
rowGroupingColumnId |
row.groupingValue |
rowGroupingValue |
row.leafRows |
rowLeafRows |
row._valuesCache on a group row |
rowAggregatedValues |
row.getIsGrouped() |
rowIsGrouped |
row.getValue(columnId) |
getValue |
row.getUniqueValues(columnId) |
getUniqueValues |
row.getLeafRows() |
getLeafRows |
row.getParentRow() |
getParentRow |
row.getParentRows() |
getParentRows |
row.getAllCells() |
getAllCells |
row.getDisplayIndex() |
displayIndex |
table.getRow(id) |
findRow |
table.getMaxSubRowDepth() |
maxSubRowDepth |
row.renderValue(columnId) |
none |
The first group takes only the row. The second group needs more: getValue
and getUniqueValues take the Config (they run your accessors);
getParentRow, getParentRows, findRow, and maxSubRowDepth take a
RowModel (they look other rows up); getAllCells takes both the Config
and the State (it needs the column order); displayIndex takes the
Config, the State, and a RowModel.
renderValue has no counterpart because there is no renderFallbackValue
option: an absent value reads back as Value.Null and you decide what to
draw. See Values.
Row ids
Every row has an id that is unique in its row model. By default a root row's
id is its index ("0", "1") and a child's id is its parent's id plus its
own index ("0.1"). Override that with
Table.withGetRowId, which receives
the datum, its index among its siblings, and its parent's row id:
config : Table.Config Person
config =
Table.config
[ Table.column "firstName" (.firstName >> Value.String)
|> Table.withHeader "First name"
, Table.column "department" (.department >> Value.String)
|> Table.withHeader "Department"
, Table.column "salary" (.salary >> Value.Number)
|> Table.withHeader "Salary"
]
|> Table.withGetRowId (\person _ _ -> person.id)
Grouping appends to the id: a group row's id is columnId:value, and nested
groups chain with >. Value.Null keys land under "null".
Row numbers and display indexes
For a row-number column, use
Table.displayIndex, not rowIndex.
rowIndex is the row's position among its siblings at the time it was built,
so it does not follow filtering, grouping, sorting, or expansion.
displayIndex is the zero-based position in
rowsInDisplayOrder, or -1
when the row is not on the current page.
rowNumber : Table.State -> Table.RowModel Person -> Table.Row Person -> String
rowNumber state model row =
let
position : Int
position =
Table.displayIndex config state model row
in
if position < 0 then
""
else
String.fromInt (position + 1)
There is no cache behind it, so it walks the display list once per call. If you are numbering every row, number the list you already mapped over instead of calling this per row.
Access row values
Table.getValue reads one cell of one
row by column id. It returns a Value, not a String:
firstNameOf : Table.Row Person -> String
firstNameOf row =
Value.toString (Table.getValue config row "firstName")
An unknown column id, or a column with no accessor, gives Value.Null
rather than an error. On a group row, getValue reads the aggregated value
when the column has one.
Table.getUniqueValues is the
list form that faceting and grouping use. A column with
withGetUniqueValues decides
its own; otherwise the cell value is wrapped in a one-item list.
departmentValues : Table.Row Person -> List Value.Value
departmentValues row =
Table.getUniqueValues config row "department"
Access original row data
Table.rowOriginal gives back the
exact record you put in, untouched by any accessor. This is the way to reach
fields you never defined a column for, and it is typed, so no casting:
originalOf : Table.Row Person -> String
originalOf row =
(Table.rowOriginal row).firstName
On a group row, rowOriginal is the first leaf row's datum. Check
rowIsGrouped before treating it as
a real record.
Sub rows
Grouping and expanding give rows children. Tell the core row model how to
reach the children of your own nested data with
Table.withSubRows.
rowSubRows: the row's children, as rows.rowOriginalSubRows: the raw childrenConfig.getSubRowsreturned.rowDepth:0for root rows,1for their children, and so on. Useful for indenting:
indent : Table.Row Person -> String
indent row =
String.repeat (Table.rowDepth row) " "
rowParentId: the parent's id, when there is one.getParentRowandgetParentRows: the parent, and the ancestors from the root down. Both take aRowModelto look ids up in:
ancestorIds : Table.RowModel Person -> Table.Row Person -> List String
ancestorIds model row =
List.map Table.rowId (Table.getParentRows model row)
getLeafRows: every descendant, depth first, not including the row itself.maxSubRowDepth: the deepest depth in a row model. A flat model is0.
deepestRow : Table.State -> Int
deepestRow state =
Table.maxSubRowDepth (Table.coreRowModelFromList config state people)
Group rows
The grouped stage inserts rows that stand for a group rather than a datum.
rowIsGrouped tells them apart,
rowGroupingColumnId says
which column the group is on,
rowGroupingValue is the value
it groups by, and rowLeafRows is
what it was built from:
groupLabel : Table.Row Person -> String
groupLabel row =
if Table.rowIsGrouped row then
Value.toString (Table.rowGroupingValue row)
++ " ("
++ String.fromInt (List.length (Table.rowLeafRows row))
++ ")"
else
""
rowAggregatedValues is the
group row's aggregates keyed by column id. Every leaf column gets an entry,
Value.Null included, so getValue on a group row never falls through to a
leaf's accessor. See Grouping and
Aggregation.
More row APIs
The per-feature row functions live with their features:
getIsRowSelected and
toggleRowSelected in
Row Selection,
getIsExpanded and
toggleExpanded in
Expanding,
getIsRowPinned and
pinRow in
Row Pinning.
To get from a row to the cells you render, see Cells.