Skip to main content

Table Overview

A table runs its pipeline and returns two things: fields and rows.

A table pipeline is explained elsewhere (provide link).

.fields

fields is an array of Field elements. A Field is an object that describes a value found in a row. At minimum it will have a name and a type. It may also have a label, valueLabels, or even arbitrary data, all of which is passed along to a renderer.

// fields:
[
{ "name": "uuid", "type": "string" },
{ "name": "S1", "label": "Gender", "type": "number" },
{ "name": "Q1", "label": "Customer Satisfaction", "type": "number" },
...
]

.rows

Rows is an array of Row elements. A Row element is an object with a property for each field. The name of the property matches the name of the field. A value could be a string, a number, or any valid JSON token (e.g., an object, boolean or null).

// rows:
[
{ "uuid": "AAB-FXGXY-BTX", "S1": 1, "Q1": 2 },
{ "uuid": "AAB-XBJMT-HUA", "S1": 1, "Q1": 3 },
{ "uuid": "AAE-FYPXK-QPY", "S1": 2, "Q1": 1 },
{ "uuid": "AAF-GFBBR-NGH", "S1": 1, "Q1": 5 },
{ "uuid": "AAG-FRRSQ-CM3", "S1": 2, "Q1": 4 },
]

.dataPlugins

Plugins can modify the rows and fields returned.

const hackDataPlugin = (args) => {
const { fields, rows } = args;
// add a row
const newRows = [
...(rows || []),
{ label: "Sample Size", "x1": 100 }
];
return {
...args,
rows: newRows
}
}

.tableSettings

There are probably some settings that the table will ask for somewhere in the UI.

.renderTableplugins

Plugins can modify the renderTable output.

.renderTable

The fields, rows and tableSettings described above are passed into a render function.

It looks something like this, but a bit more complex since renderCell can return multiple cells if it wants to.

const renderTable = (args) => {

const { fields, rows, tableSettings, plugins } = args;

// returns some stuff
let renderedRows = [];
if(rows && fields){
for(let row of rows){
let renderedRow = []; // should I refactor out a renderRow function with renderRow plugins? it would potentially return multiple rows
for(let field of fields){
const c = renderCell({ ...args, field, row }); // in real life could potentially return multiple cells (not handled here)
renderedRow.push(c);
}
renderedRows.push(renderedRow);
}
}

// apply plugins if any
if( plugins ){
for(let plugin of plugins ){
renderedRows = plugin({ ...args, renderedRows });
}
}

return renderedRows;
}

.renderCellPlugins

Plugins can modify the renderCell output. A plugin is called for every cell, so it's the plugin's responsibility to decide (by looking at fieldObj or something) whether or not to modify the cell.

.renderCell

// returns a cell object (JSON). See renderPCell or renderXCell docs.
const renderCell = (args) => {

let renderedCell;

// ...
const { row, field } = args;

// something like this:
renderedCell = {
...field, // add everything the field has
};

// loop through all the prior fields that have a prop like .rowHeader meaning they come from row dims (not col dims)
// add those props
// todo:
{

}

// add the value?
renderedCell.value = row[field.name];

if( field.type === "string" ){
renderedCell.formatCategory = "General";
}
else if( field.type === "number" ){
renderedCell.formatCategory = "Custom";
renderedCell.customFormat = field.valueFormat || row.valueFormat || "0.2f"; // where does row valueFormat come from? (do i need to look for it)?
}
else if( field.type === "object" ){
// todo (show label or value)??
renderedCell.value = row[field.name]?.label; // ??
}
else{
// boolean, date, unknown
}

// apply plugins if any
if( plugins ){
for(let plugin of plugins){
renderedCell = plugin({ ...args, renderedCell });
}
}

return renderedCell;

}

customLowNCellPlugin

const customLowNCellPlugin = (args, pluginArgs) => {

const newCell = { ...args.renderedCell };

const lowN = pluginArgs.lowN || args.props.lowN;
if( newCell.value < lowN ){
// todo: mask the value somehow
newCell.value = "**";
newCell.backgroundColor = "red";
}

return newCell;

}

showFreqCellPlugin

const showFreqCellPlugin = (args) => {

const originalCell = args.renderedCell;

const { row, field } = args;
let newFreqCell = {
// something like this:
value: row[field.name]?.freq;
formatCategory = "Custom";
customFormat = ",.0f";
}

// actually i don't like this returning of arrays. i think instead i'll do e.., .cellsBelow = [newFreqCell]
// this returns the new cell below the original
return [originalCell, newFreqCell];

// actually i don't like this returning of arrays. i think instead i'll do e.., .cellsNextTo = [newFreqCell]
// this would return the new cell to the right of the original
return [[originalCell, newFreqCell]];

}

showStandardTestResultsPlugin

const showStandardTestResultsPlugin = (args) => {

const originalCell = args.renderedCell;

const { row, field } = args;
let newCell = {
// something like this:
value: row[field.name]?.testResults;
// todo
}

// this returns the new cell below the original
return {
...originalCell,
belowCell: newCell // something like this?
}


}