import { DataGridProvider, FetchByOffsetGridParameters, FetchByOffsetGridResults, GridItem, GridBodyItem, GridHeaderItem } from 'ojs/ojdatagridprovider'; import { EventTargetMixin } from 'ojs/ojeventtarget'; interface DataParams { dataArray?: Array, columnHeaders?: Array } export class SampleDataGridProvider implements DataGridProvider { addEventListener: () => void; removeEventListener: () => void; private readonly totalRows; private readonly totalCols; private readonly columnKeys; constructor(protected dataParams?: DataParams) { if (this.dataParams?.columnHeaders) { this.columnKeys = this.dataParams.columnHeaders; } else { this.columnKeys = this.dataParams?.dataArray?.[0] ? Object.keys(this.dataParams.dataArray[0]) : []; } // Treats each key in the data as a column this.totalCols = this.columnKeys.length; // Counts the number of individual entries in the json data as rows this.totalRows = this.dataParams?.dataArray ? this.dataParams.dataArray.length : -1; } public fetchByOffset( parameters: FetchByOffsetGridParameters ): Promise> { return new Promise((resolve: Function) => { const rowOffset = parameters.rowOffset; const columnOffset = parameters.columnOffset; // Minimum of the rowCount given in parameters and the number of rows remaining until the end of the data const rowCount = Math.min(parameters.rowCount, this.totalRows - rowOffset); const columnCount = Math.min(parameters.columnCount, this.totalCols - columnOffset); // True if the final row specified by parameters is greater than the total number of rows const rowDone = rowOffset + rowCount >= this.totalRows; const columnDone = columnOffset + columnCount >= this.totalCols; // Will have start column for the headers be columnOffset and continue up through columnOffset + columnCount const columnHeader = this.getColumnHeaderResults(columnOffset, (columnOffset + columnCount)); const databody = this.getDatabodyResults(rowOffset, (rowOffset + rowCount), columnOffset, (columnOffset + columnCount)); const next = null; const results = { databody: databody, columnHeader: columnHeader } resolve( new this.FetchByOffsetGridResults( parameters, rowDone, columnDone, rowOffset, columnOffset, rowCount, columnCount, this.totalRows, this.totalCols, results, next) ); }); } private getDatabodyResults(rowStart: number, rowEnd: number, columnStart: number, columnEnd: number): Array> | undefined { if (this.dataParams?.dataArray?.[0]) { // Use the new list of the keys, if provided, else use the provided data, which will become the column headers const columnKeys = this.columnKeys; const databody = []; // Iterates through every row in the region fetched for (let i = rowStart; i < rowEnd; i++) { const arrayOfIndex = this.dataParams.dataArray[i]; // Iterates through every column of the current row for (let j = columnStart; j < columnEnd; j++) { // Sets the extent of the cell vertically to correspond to one row let rowExtent = 1; // Sets the extent of the cell horizontally to correspond to one column let columnExtent = 1; // Get the value from the data const value = { data: arrayOfIndex[columnKeys[j]] } as any; // Creates GridBodyItem with value, extents and indexes const item: GridBodyItem = new this.GridBodyItem(rowExtent, columnExtent, i, j, {}, value); databody.push(item); }; } return databody; } return null; } private getColumnHeaderResults(startIndex: number, endIndex: number): Array> | undefined { if (this.dataParams?.dataArray?.[0]) { // Use the new list of the keys, if provided, else use the provided data, which will become the column headers const columnKeys = this.columnKeys; const results = []; for (let i = startIndex; i < endIndex; i++) { const value = { data: columnKeys[i] } as any; // Sets index to i, extent to 1, level to 0 (there's only one column header level), and depth to 1 // Add metadata for sortability here const item: GridHeaderItem = new this.GridHeaderItem(i, 1, 0, 1, new this.GridHeaderMetadata(null, null), value); results.push(item); } return results; } return null; } public getCapability(capabilityName: string): any { return null; } public isEmpty(): 'yes' | 'no' | 'unknown' { return (this.dataParams.dataArray.length <= 0) ? 'yes' : 'no'; // Returns 'yes' if not given any data, returns 'no' otherwise } private FetchByOffsetGridResults = class implements FetchByOffsetGridResults { constructor( public readonly fetchParameters: FetchByOffsetGridParameters, public readonly rowDone: boolean, public readonly columnDone: boolean, public readonly rowOffset: number, public readonly columnOffset: number, public readonly rowCount: number, public readonly columnCount: number, public readonly totalRowCount: number, public readonly totalColumnCount: number, public readonly results: { readonly databody?: Array>, }, public readonly version: number, public next?: Promise> ) { } }; private GridBodyItem = class implements GridBodyItem { constructor( public readonly rowExtent: number, public readonly columnExtent: number, public readonly rowIndex: number, public readonly columnIndex: number, public readonly metadata: Object, public readonly data: D ) { } }; private GridHeaderItem = class implements GridHeaderItem { constructor( public readonly index: number, public readonly extent: number, public readonly level: number, public readonly depth: number, public readonly metadata: Object, public readonly data: D ) { } }; private GridItem = class implements GridItem { constructor(public readonly metadata: Object, public readonly data: D) { } }; private GridHeaderMetadata = class { constructor(public readonly sortDirection?: 'ascending' | 'descending', public readonly sortable?: boolean) { } }; } // This is a convenience for registering addEventListener/removeEventListener EventTargetMixin.applyMixin(SampleDataGridProvider);