Skip to content

Commit

Permalink
feat: add Footer Totals Row and fix footer styling
Browse files Browse the repository at this point in the history
  • Loading branch information
ghiscoding committed Jun 15, 2024
1 parent 0df258c commit 17e798f
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { GridContextMenuComponent } from './examples/grid-contextmenu.component'
import { GridCustomTooltipComponent } from './examples/grid-custom-tooltip.component';
import { GridDraggableGroupingComponent } from './examples/grid-draggrouping.component';
import { GridEditorComponent } from './examples/grid-editor.component';
import { GridFooterTotalsComponent } from './examples/grid-footer-totals.component';
import { GridExcelFormulaComponent } from './examples/grid-excel-formula.component';
import { GridFormatterComponent } from './examples/grid-formatter.component';
import { GridFrozenComponent } from './examples/grid-frozen.component';
Expand Down Expand Up @@ -53,6 +54,7 @@ const routes: Routes = [
{ path: 'custom-tooltip', component: GridCustomTooltipComponent },
{ path: 'editor', component: GridEditorComponent },
{ path: 'excel-formula', component: GridExcelFormulaComponent },
{ path: 'footer-totals', component: GridFooterTotalsComponent },
{ path: 'formatter', component: GridFormatterComponent },
{ path: 'frozen', component: GridFrozenComponent },
{ path: 'headerbutton', component: GridHeaderButtonComponent },
Expand Down
5 changes: 5 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@
36- Excel Export Formulas
</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" [routerLink]="['/footer-totals']">
37- Footer Totals Row
</a>
</li>
</ul>
</section>

Expand Down
4 changes: 3 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { CustomFooterComponent, GridHeaderFooterComponent } from './examples/gri
import { EditorNgSelectComponent } from './examples/editor-ng-select.component';
import { FilterNgSelectComponent } from './examples/filter-ng-select.component';
import { GridAddItemComponent } from './examples/grid-additem.component';
import { GridAngularComponent } from './examples/grid-angular.component';
import { GridAutoHeightComponent } from './examples/grid-autoheight.component';
import { GridBaseRowEditingComponent } from './examples/grid-base-row-editing.component';
import { GridBasicComponent } from './examples/grid-basic.component';
Expand All @@ -28,7 +29,7 @@ import { GridCustomTooltipComponent } from './examples/grid-custom-tooltip.compo
import { GridDraggableGroupingComponent } from './examples/grid-draggrouping.component';
import { GridEditorComponent } from './examples/grid-editor.component';
import { GridExcelFormulaComponent } from './examples/grid-excel-formula.component';
import { GridAngularComponent } from './examples/grid-angular.component';
import { GridFooterTotalsComponent } from './examples/grid-footer-totals.component';
import { GridFormatterComponent } from './examples/grid-formatter.component';
import { GridFrozenComponent } from './examples/grid-frozen.component';
import { GridGraphqlComponent } from './examples/grid-graphql.component';
Expand Down Expand Up @@ -108,6 +109,7 @@ export function appInitializerFactory(translate: TranslateService, injector: Inj
GridDraggableGroupingComponent,
GridEditorComponent,
GridExcelFormulaComponent,
GridFooterTotalsComponent,
GridFormatterComponent,
GridFrozenComponent,
GridGraphqlComponent,
Expand Down
28 changes: 28 additions & 0 deletions src/app/examples/grid-footer-totals.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div id="demo-container" class="container-fluid">
<h2>
{{title}}
<button class="btn btn-outline-secondary btn-sm ms-3" (click)="toggleDarkMode()"
data-test="toggle-dark-mode">
<span class="mdi mdi-theme-light-dark"></span>
<span>Toggle Dark Mode</span>
</button>
<span class="float-end">
<a style="font-size: 18px"
target="_blank"
href="https://github.com/ghiscoding/Angular-Slickgrid/blob/master/src/app/examples/grid-footer-totals.component.ts">
<span class="mdi mdi-link-variant"></span> code
</a>
</span>
</h2>
<div class="subtitle"
[innerHTML]="subTitle"></div>

<angular-slickgrid gridId="grid37"
[columnDefinitions]="columnDefinitions"
[gridOptions]="gridOptions"
[dataset]="dataset"
(onAngularGridCreated)="angularGridReady($event.detail)"
(onCellChange)="handleOnCellChange($event.detail.eventData, $event.detail.args)"
(onColumnsReordered)="handleOnColumnsReordered()">
</angular-slickgrid>
</div>
125 changes: 125 additions & 0 deletions src/app/examples/grid-footer-totals.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { AngularGridInstance, Column, Editors, FieldType, GridOption, OnCellChangeEventArgs, } from './../modules/angular-slickgrid';

const NB_ITEMS = 100;

@Component({
templateUrl: './grid-footer-totals.component.html'
})
export class GridFooterTotalsComponent implements OnDestroy, OnInit {
private _darkMode = false;
title = 'Example 37: Footer Totals Row';
subTitle = `Display a totals row at the end of the grid.`;

columnDefinitions: Column[] = [];
gridOptions!: GridOption;
dataset!: any[];
angularGrid!: AngularGridInstance;

angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
this.updateAllTotals();
}

ngOnInit(): void {
this.defineGrid();

// mock a dataset
this.dataset = this.loadData(NB_ITEMS);
}

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

/* 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 }
});
}
this.columnDefinitions = columnDefs;

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

loadData(itemCount: 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 < this.columnDefinitions.length; 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.angularGrid.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.angularGrid.slickGrid?.getColumns().length || 0;
while (columnIdx--) {
this.updateTotal(columnIdx);
}
}

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

let total = 0;
let i = this.dataset.length;
while (i--) {
total += (parseInt(this.dataset[i][columnId], 10) || 0);
}
const columnElement = this.angularGrid.slickGrid?.getFooterRowColumn(columnId);
if (columnElement) {
columnElement.textContent = `Sum: ${total}`;
}
}
}
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 24 - 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')}/footer-totals`);
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 17e798f

Please sign in to comment.