Models
Models provide the primary API for interacting with SheetXL and they are implemented as plain TypeScript libraries that can be used in any Javascript environment (browser, node, other).
While SheetXL has many interfaces the most commonly used interfaces are:
-
IWorkbookModel - A collection of sheets and generally the primary interface for ranges and loading and saving state.
-
IWorkbookRange - The primary interface for working with data.
-
ICellStyle - Contains the formatting for a range of cells or cell headers.
-
ISheetHeaderRange - Used for reading or updating headers.
-
ISheetView and IWorkbookView - Used for views specific attributes.
WorkbookModel
Workbook models contain the the most common interaction mechanisms within SheetXL.
To create a workbook model simply import the @sheetxl/models package and create a new instance.
// create a default workbook
const workbookModel:IWorkbookModel = new WorkbookModel();
Ranges
The simplest way to interact with data is by using IWorkbookRange. This can be accessed from the IWorkbookModel.
// create a default workbook with no data
const workbookModel:IWorkbookModel = new WorkbookModel();
// get a range that can be iterated or updated
const range:IWorkbookRange = workbookModel.getRange('Sheet1!A1:E5000');
To listen for data range changes use addRangeListener.
// create a default workbook
const workbookModel:IWorkbookModel = new WorkbookModel();
// get a range that can be iterators or allow for updates
const listener =
(range: IWorkbookRange | null, sheet: ISheetModel | null, workbook: IWorkbookModel | null): void => {
// do something with the range.
};
const removeListener:RemoveListener = addRangeListener(
workbookModel.getRange('Sheet1!A1:E5000'), listener);
// call removeListener() to remove the listener when finished
Working with Data
Reading Data Values
Spreadsheets can have very large amounts of data and often contain a huge number of empty elements. (Excel has 1.6 billion cells even for an empty spreadsheet).
To enable high performance read-access IWorkbookRange.forEach is used to iterate over the data skipping any blank cells.
const options:CellVisitorOptions = {
includeEmpty: false; // This is the default but shown for illustration purposes.
}
workbookModel.getRange('Sheet1!A1:E5000').forEach(
(value: ICellValue, coord: CellCoords, context: CellVisitorContext) => {
// only cells with a value will be visited
}, options);
Writing Data Values
IWorkbookRange.update is used for updates and to support batch and non-batch.
// update a single cell
const updateExample1:RangeUpdateValue = 100;
workbookModel.getRange('Sheet1!A1').update(updateExample1);
// update a range of cells
const updateExample2:RangeUpdateValue = [[100, 200], [300, 400]];
workbookModel.getRange('Sheet1!A1').update(updateExample2);
To support batching of non-contiguous data see ISheetModel.setCellPairs.
Formatting
ICellStyle is used to format cell styles on a range of cells or cell headers. The cell style is contained in ICellModel.style interface.
Reading Cell Styles Values
Cell Styles are accessed as a property on the ICellModel interface which is available from the IWorkbookRange interface or from the forEach.
// Note recommended if access many values; use forEach to iterate over data
const cell:ICellModel = workbookModel.getRange('Sheet1!A1').cell();
const style:ICellStyle = cell.style;
workbookModel.getRange('Sheet1!A1:E5').forEach(
(value: ICellValue, coord: CellCoords, context: CellVisitorContext) => {
// only cells with a value will be visited. A complex ICellModel can be accessed using the context.
const cell:ICellModel = context.getCell();
const style:ICellStyle = cell.style;
}, options);
Writing Cell Styles Values
Writing cells styles is similar to writing values and the IWorkbookRange.update is used. The biggest addition to data values is that cell styles are complex objects that support 'partial' updates.
To update a style a JSON object that mirrors the ICellStyle interface is used but with the following rules.
- If value is a valid type it will replace the existing value.
- If value is
null
it will 'default' the value to the original style value. - If the value is
undefined
or not present it will be ignored. - If the value is a
string
it will be parsed similar to CSS (See individual style property for details); for example a border can be set by using the following:1px solid red
or a font can be set by using14pt Arial
. - If the value is a function then the function will be called with the original value and the result will be applied
Note - This can have negative performance impacts so use carefully
.
// update style to several cells
const updateExample1:RangeUpdateValue = {
style: {
font: '14pt Arial',
fill: 'aliceBlue', // PresetColor.AliceBlue,
}
};
workbookModel.getRange('Sheet1!A1:E5').update(updateExample1);
// now revert the fill to the normal style
workbookModel.getRange('Sheet1!A1:E5').update({
style: {
fill: null,
}
});
Headers
Reading or Updating Headers
Headers contain information that is applied to entire rows or columns such as:
- Size (Width/Height)
- Visibility
- Custom Titles
// Set 4 columns
const updateHeader:CellHeaderUpdate = {
size: 120
};
workbookModel.getRange('Sheet1!B:E').updateColumns(updateHeader);
// Hide some rows
const updateHeader:CellHeaderUpdate = {
style: {
hidden: true,
}
};
workbookModel.getRange('Sheet1!2:20').updateRows(updateHeader);
As an optimization headers contain styling information for cell ranges that span the entire header, for example column width or row height, but as a best practice it is recommended to use the ICellRange to update styling.
Inserting/Removing Cells
Inserting and removing cells or headers (rows/columns) is supported via the ICellRange interface using IWorkbookRange.insertCells and IWorkbookRange.removeCells.
// insert column
workbookModel.getRange('Sheet1!B:E').insertCells('right');
// remove row
workbookModel.getRange('Sheet1!2:2').removeCells('up');
Views
Workbooks and Sheets have layout information that is not part of the data but only effects how information is displayed for a given user/context.
Reading Views
// find out if the row grid lines are visible
const view:ISheetView = workbookModel.getSheet('Sheet1').getView();
const isShowRowGridLines:boolean = view.showRowGridlines;
Writing Views
// set showRowGridLines to false
workbookModel.getSheet('Sheet1').setView({
showRowGridlines: true,
});
Listening to View Changes
const listener:ISheetModelListener = {
onViewChange?(update: ISheetView | null | undefined): void => {
// something interesting here
}
};
const removeListener = workbookModel.getSheet('Sheet1').addListener(listener);
// don't forget to removelistener when finished
removeListener();
Themes
Cell Styles use Themes, implemented as IDocTheme, to determine colors, fonts, and other visual effects. These are based on the OOXML standards used by Microsoft Excel and (mostly) Google Sheets.
The theme is generally embedded within the Sheet or Workbook so if these are shared the themes will also be shared.
A working example is available at CodeSandbox/custom-app-theme
Loading and Saving State
Most models implement the JSONSerializable interface which enables a common API for loading and saving state as JSON. If a model implements JSONSerializable then by convention it's first argument in the constructor is a matching JSON object. This is done to avoid initializing objects twice.
const asJSON:JSONSerializable<WorkbookJSON> = workbookModel.toJSON();
// save asJSON to local storage or db
const asJSON:JSONSerializable<WorkbookJSON> = { /* from db or local storage */ };
// preferred way
const workbookModel:IWorkbookModel = new WorkbookModel(asJSON);
// works but discouraged
const workbookModel2:IWorkbookModel = new WorkbookModel();
workbookModel2.fromJSON(asJSON);
Create workbook model from initial data
A common use case is to just display a Workbook with initial data.
The WorkbookModel constructor also takes a 2D array of ICellValues.
const workbook:IWorkbookModel = new WorkbookModel([
[1,2,3],
[4,5,6],
[7,8,9]
]);
Import and Exporting
Import and Exporting file formats other than the native SheetXL JSON type is done using using the @sheetxl/io package. This is MIT open-sourced and is available on github.
The formats, including native JSON, currently support are:
- CSV
- Excel
- SheetXL JSON (native)
The @sheetxl/sheet-mui/DefaultIORegistry
has methods that dynamically import the @sheetxl/io package to convenient import and export.This code is also MIT open-sourced and is available on
github.
/**
* Import a workbook from an ArrayBuffer.
*/
DefaultIORegistry.importFromArrayBuffer(
arrayBuffer: ArrayBuffer | Promise<ArrayBuffer>,
key: string,
options: MultiImportWorkbookOptions=null
): Promise<IWorkbookModel>;
/**
* Will try to read from local file system using available IO handlers.
* The input can be either a File, a Promise<File>, or a string.
* If a string is provided, if should be either an extension or a mimetype
* that will be passed to the accept attribute of an
* input: @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept.
* @param input
* @param options
* @returns a promise that resolves to an ImportResults object.
*
* @remarks
* This is just a wrapper around CommonUtils.openFile, DefaultIORegistry.importFromArrayBuffer,
* and notification.
*/
DefaultIORegistry.importFromFile(
input: File | Promise<File> | string=null,
options: MultiImportWorkbookOptions=null,
notifier?: Notifier
): Promise<ImportResults>;
/**
* Exports to the local file system attempting to use the fileName provided. This will
* use the exportType to determine the export handler to use.
* @returns a Promise indicating success or failure.
*/
DefaultIORegistry.exportToFile(
workbookModel: IWorkbookModel,
fileName: string | null,
exportType?: ExportType
): Promise<boolean>;
If another format is needed or something is missing please let me know. I am working with SheetJS and custom libraries as required.
More Models Examples
All (most) UI operations are available via the models and can be access via the IWorkbookRange interface.
Another way to see a set of examples is to use the use developer console of full demo:
via demo console
- Open the standalone demo at standalone demo
- Open the developer tools (Ctl+Shift+I)
- In the console window type
sheetXl.moreExamples()