Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ghiscoding committed Jun 15, 2024
2 parents dd0cc70 + 4f6226e commit 28ce6b6
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/examples/slickgrid/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Example33 from './Example33';
import Example34 from './Example34';
import Example35 from './Example35';
import Example36 from './Example36';
import Example37 from './Example37';

const routes: Array<{ path: string; route: string; component: any; title: string; }> = [
{ path: 'example1', route: '/example1', component: <Example1 />, title: '1- Basic Grid / 2 Grids' },
Expand Down Expand Up @@ -72,6 +73,7 @@ const routes: Array<{ path: string; route: string; component: any; title: string
{ path: 'example34', route: '/example34', component: <Example34 />, title: '34- Real-Time Trading Platform' },
{ path: 'example35', route: '/example35', component: <Example35 />, title: '35- Row Based Editing' },
{ path: 'example36', route: '/example36', component: <Example36 />, title: '36- Excel Export Formulas' },
{ path: 'example37', route: '/example37', component: <Example37 />, title: '37- Footer Totals Row' },
];

export default function Routes() {
Expand Down
181 changes: 181 additions & 0 deletions src/examples/slickgrid/Example37.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import {
type Column,
FieldType,
type GridOption,
SlickgridReact,
Editors,
type OnCellChangeEventArgs,
type SlickgridReactInstance,
} from '../../slickgrid-react';
import React from 'react';
import BaseSlickGridState from './state-slick-grid-base';

const NB_ITEMS = 100;

interface State extends BaseSlickGridState { }

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Props { }

export default class Example2 extends React.Component<Props, State> {
private _darkMode = false;

title = 'Example 37: Footer Totals Row';
subTitle = `Display a totals row at the end of the grid.`;

reactGrid!: SlickgridReactInstance;
resizerPaused = false;

constructor(public readonly props: Props) {
super(props);

this.state = {
gridOptions: undefined,
columnDefinitions: [],
dataset: [],
};
}

componentDidMount() {
document.title = this.title;

// define the grid options & columns and then create the grid itself
this.defineGrid();
}

componentWillUnmount() {
document.querySelector('.panel-wm-content')!.classList.remove('dark-mode');
document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme = 'light';
}

reactGridReady(reactGrid: SlickgridReactInstance) {
this.reactGrid = reactGrid;
this.updateAllTotals();
}

/* Define grid Options and Columns */
defineGrid() {
const columnDefs: Column[] = [];
for (let i = 0; i < 10; i++) {
columnDefs.push({
id: i,
name: String.fromCharCode('A'.charCodeAt(0) + i),
field: String(i),
type: FieldType.number,
width: 58,
editor: { model: Editors.integer }
});
}

const gridOptions: GridOption = {
autoEdit: true,
autoCommitEdit: true,
editable: true,
darkMode: this._darkMode,
gridHeight: 450,
gridWidth: 800,
enableCellNavigation: true,
rowHeight: 30,
createFooterRow: true,
showFooterRow: true,
footerRowHeight: 28,
};

this.setState((state: State, props: Props) => ({
...this.state,
columnDefinitions: columnDefs,
gridOptions,
dataset: this.loadData(NB_ITEMS, columnDefs.length),
}));
}

loadData(itemCount: number, colDefLn: number) {
// mock a dataset
const datasetTmp: any[] = [];
for (let i = 0; i < itemCount; i++) {
const d = (datasetTmp[i] = {} as any);
d.id = i;
for (let j = 0; j < colDefLn; j++) {
d[j] = Math.round(Math.random() * 10);
}
}
return datasetTmp;
}

handleOnCellChange(_e: Event, args: OnCellChangeEventArgs) {
this.updateTotal(args.cell);
}

handleOnColumnsReordered() {
this.updateAllTotals();
}

toggleDarkMode() {
this._darkMode = !this._darkMode;
this.toggleBodyBackground();
this.reactGrid.slickGrid?.setOptions({ darkMode: this._darkMode });
this.updateAllTotals();
}

toggleBodyBackground() {
if (this._darkMode) {
document.querySelector<HTMLDivElement>('.panel-wm-content')!.classList.add('dark-mode');
document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme = 'dark';
} else {
document.querySelector('.panel-wm-content')!.classList.remove('dark-mode');
document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme = 'light';
}
}

updateAllTotals() {
let columnIdx = this.reactGrid.slickGrid?.getColumns().length || 0;
while (columnIdx--) {
this.updateTotal(columnIdx);
}
}

updateTotal(cell: number) {
const columnId = this.reactGrid.slickGrid?.getColumns()[cell].id as number;

let total = 0;
let i = this.state.dataset!.length || 0;
while (i--) {
total += (parseInt(this.state.dataset![i][columnId], 10) || 0);
}
const columnElement = this.reactGrid.slickGrid?.getFooterRowColumn(columnId);
if (columnElement) {
columnElement.textContent = `Sum: ${total}`;
}
}

render() {
return !this.state.gridOptions ? '' : (
<div id="demo-container" className="container-fluid">
<h2>
{this.title}
<button className="btn btn-outline-secondary btn-sm btn-icon ms-2" onClick={() => this.toggleDarkMode()} data-test="toggle-dark-mode">
<i className="mdi mdi-theme-light-dark"></i>
<span>Toggle Dark Mode</span>
</button>
<span className="float-end font18">
see&nbsp;
<a target="_blank"
href="https://github.com/ghiscoding/slickgrid-react/blob/master/src/examples/slickgrid/Example37.tsx">
<span className="mdi mdi-link-variant"></span> code
</a>
</span>
</h2>
<div className="subtitle" dangerouslySetInnerHTML={{ __html: this.subTitle }}></div>

<SlickgridReact gridId="grid37"
columnDefinitions={this.state.columnDefinitions}
gridOptions={this.state.gridOptions}
dataset={this.state.dataset}
onReactGridCreated={$event => this.reactGridReady($event.detail)}
onCellChange={$event => this.handleOnCellChange($event.detail.eventData, $event.detail.args)}
onColumnsReordered={$event => this.handleOnColumnsReordered()}
/>
</div>
);
}
}
57 changes: 57 additions & 0 deletions test/cypress/e2e/example37.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
describe('Example 37 - Footer Totals Row', () => {
const fullTitles = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
const GRID_ROW_HEIGHT = 33;

it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/example37`);
cy.get('h2').should('contain', 'Example 37: Footer Totals Row');
});

it('should have exact Column Header Titles in the grid', () => {
cy.get('#grid37')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});

it('should have a total sum displayed in the footer for each column', () => {
for (let i = 0; i < 10; i++) {
cy.get(`.slick-footerrow-columns .slick-footerrow-column:nth(${i})`)
.should($span => {
const totalStr = $span.text();
const totalVal = Number(totalStr.replace('Sum: ', ''));

expect(totalStr).to.contain('Sum:');
expect(totalVal).to.gte(400);
});

}
});

it('should be able to increase cell value by a number of 5 and expect column sum to be increased by 5 as well', () => {
let cellVal = 0;
let totalVal = 0;
const increasingVal = 50;

cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`)
.should($span => {
cellVal = Number($span.text());
expect(cellVal).to.gte(0);
});
cy.get('.slick-footerrow-columns .slick-footerrow-column:nth(0)')
.should($span => {
totalVal = parseInt($span.text().replace('Sum: ', ''));
expect(totalVal).to.gte(400);
});

cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).click();
cy.get('.editor-0').type(`${increasingVal}{enter}`);
cy.wait(1);

cy.get('.slick-footerrow-columns .slick-footerrow-column:nth(0)')
.should($span => {
const newTotalVal = parseInt($span.text().replace('Sum: ', ''));
expect(newTotalVal).to.eq(totalVal - cellVal + increasingVal);
});
});
});

0 comments on commit 28ce6b6

Please sign in to comment.