addInvalidCellListener
The addInvalidCellListener
method registers a listener function with the Store
that will be called whenever invalid data was attempted to be written to a Cell
.
addInvalidCellListener(
tableId: IdOrNull,
rowId: IdOrNull,
cellId: IdOrNull,
listener: InvalidCellListener<Store>,
mutator?: boolean,
): string
Type | Description | |
---|---|---|
tableId | IdOrNull | |
rowId | IdOrNull | |
cellId | IdOrNull | |
listener | InvalidCellListener<Store> | The function that will be called whenever an attempt to write invalid data to the matching |
mutator? | boolean | An optional boolean that indicates that the listener mutates |
returns | string | A unique |
The provided listener is an InvalidCellListener
function, and will be called with a reference to the Store
, the Id
of the Table
, the Id
of the Row
, and the Id
of Cell
that was being attempted to be changed. It is also given the invalid value of the Cell
, which could have been of absolutely any type. Since there could have been multiple failed attempts to set the Cell
within a single transaction, this is an array containing each attempt, chronologically.
You can either listen to a single Cell
(by specifying the Table
Id
, Row
Id
, and Cell
Id
as the method's first three parameters) or invalid attempts to change any Cell
(by providing null
wildcards).
All, some, or none of the tableId
, rowId
, and cellId
parameters can be wildcarded with null
. You can listen to a specific Cell
in a specific Row
in a specific Table
, any Cell
in any Row
in any Table
, for example - or every other combination of wildcards.
Use the optional mutator parameter to indicate that there is code in the listener that will mutate Store
data. If set to false
(or omitted), such mutations will be silently ignored. All relevant mutator listeners (with this flag set to true
) are called before any non-mutator listeners (since the latter may become relevant due to changes made in the former). The changes made by mutator listeners do not fire other mutating listeners, though they will fire non-mutator listeners.
Special note should be made for how the listener will be called when a TablesSchema
is present. The listener will be called:
- if a
Table
is being updated that is not specified in theTablesSchema
, - if a
Cell
is of the wrong type specified in theTablesSchema
, - if a
Cell
is omitted and is not defaulted in theTablesSchema
, - or if an empty
Row
is provided and there are noCell
defaults in theTablesSchema
.
The listener will not be called if a Cell
that is defaulted in the TablesSchema
is not provided, as long as all of the Cells that are not defaulted are provided.
To help understand all of these schema-based conditions, please see the TablesSchema
example below.
Examples
This example registers a listener that responds to any invalid changes to a specific Cell
.
import {createStore} from 'tinybase';
const store = createStore().setTables({
pets: {fido: {species: 'dog', color: 'brown'}},
});
const listenerId = store.addInvalidCellListener(
'pets',
'fido',
'color',
(store, tableId, rowId, cellId, invalidCells) => {
console.log('Invalid color cell in fido row in pets table');
console.log(invalidCells);
},
);
store.setCell('pets', 'fido', 'color', {r: '96', g: '4B', b: '00'});
// -> 'Invalid color cell in fido row in pets table'
// -> [{r: '96', g: '4B', b: '00'}]
store.delListener(listenerId);
This example registers a listener that responds to any invalid changes to any Cell
- in a Store
without a TablesSchema
. Note also how it then responds to cases where empty or invalid Row
objects, or Table
objects, or Tables
objects are provided.
import {createStore} from 'tinybase';
const store = createStore().setTables({
pets: {fido: {species: 'dog', color: 'brown'}},
});
const listenerId = store.addInvalidCellListener(
null,
null,
null,
(store, tableId, rowId, cellId) => {
console.log(
`Invalid ${cellId} cell in ${rowId} row in ${tableId} table`,
);
},
);
store.setCell('pets', 'fido', 'color', {r: '96', g: '4B', b: '00'});
// -> 'Invalid color cell in fido row in pets table'
store.setTable('sales', {fido: {date: new Date()}});
// -> 'Invalid date cell in fido row in sales table'
store.setRow('pets', 'felix', {});
// -> 'Invalid undefined cell in felix row in pets table'
store.setRow('filter', 'name', /[a-z]?/);
// -> 'Invalid undefined cell in name row in filter table'
store.setRow('sales', '2021', {forecast: undefined});
// -> 'Invalid forecast cell in 2021 row in sales table'
store.addRow('filter', /[0-9]?/);
// -> 'Invalid undefined cell in undefined row in filter table'
store.setTable('raw', {});
// -> 'Invalid undefined cell in undefined row in raw table'
store.setTable('raw', ['row1', 'row2']);
// -> 'Invalid undefined cell in undefined row in raw table'
store.setTables(['table1', 'table2']);
// -> 'Invalid undefined cell in undefined row in undefined table'
store.delListener(listenerId);
This example registers a listener that responds to any invalid changes to any Cell
- in a Store
with a TablesSchema
. Note how it responds to cases where missing parameters are provided for optional, and defaulted Cell
values in a Row
.
import {createStore} from 'tinybase';
const store = createStore().setTablesSchema({
pets: {
species: {type: 'string'},
color: {type: 'string', default: 'unknown'},
},
});
const listenerId = store.addInvalidCellListener(
null,
null,
null,
(store, tableId, rowId, cellId) => {
console.log(
`Invalid ${cellId} cell in ${rowId} row in ${tableId} table`,
);
},
);
store.setRow('sales', 'fido', {price: 5});
// -> 'Invalid price cell in fido row in sales table'
// The listener is called, because the sales Table is not in the schema
store.setRow('pets', 'felix', {species: true});
// -> 'Invalid species cell in felix row in pets table'
// The listener is called, because species is invalid...
console.log(store.getRow('pets', 'felix'));
// -> {color: 'unknown'}
// ...even though a Row was set with the default value
store.setRow('pets', 'fido', {color: 'brown'});
// -> 'Invalid species cell in fido row in pets table'
// The listener is called, because species is missing and not defaulted...
console.log(store.getRow('pets', 'fido'));
// -> {color: 'brown'}
// ...even though a Row was set
store.setRow('pets', 'rex', {species: 'dog'});
console.log(store.getRow('pets', 'rex'));
// -> {species: 'dog', color: 'unknown'}
// The listener is not called, because color is defaulted
store.delTables().setTablesSchema({
pets: {
species: {type: 'string'},
color: {type: 'string'},
},
});
store.setRow('pets', 'cujo', {});
// -> 'Invalid species cell in cujo row in pets table'
// -> 'Invalid color cell in cujo row in pets table'
// -> 'Invalid undefined cell in cujo row in pets table'
// The listener is called multiple times, because neither Cell is defaulted
// and the Row as a whole is empty
store.delListener(listenerId);
This example registers a listener that responds to any changes to a specific Cell
, and which also mutates the Store
itself.
import {createStore} from 'tinybase';
const store = createStore().setTables({
pets: {fido: {species: 'dog', color: 'brown'}},
});
const listenerId = store.addInvalidCellListener(
'pets',
'fido',
'color',
(store, tableId, rowId, cellId, invalidCells) =>
store.setCell(
'meta',
'invalid_updates',
`${tableId}_${rowId}_${cellId}`,
JSON.stringify(invalidCells[0]),
),
true,
);
store.setCell('pets', 'fido', 'color', {r: '96', g: '4B', b: '00'});
console.log(store.getRow('meta', 'invalid_updates'));
// -> {'pets_fido_color': '{"r":"96","g":"4B","b":"00"}'}
store.delListener(listenerId);
Since
v1.1.0