From 159b24516360b3a5fa54c18d532763020db8efac Mon Sep 17 00:00:00 2001 From: Nicolas Bruy?re Date: Thu, 30 Jan 2020 15:57:36 +0100 Subject: [PATCH] feat(stark-ui): add footer to table component ISSUES CLOSED: #1540 --- .../table/components/column.component.html | 5 ++ .../table/components/column.component.ts | 21 ++++++++ .../table/components/table.component.html | 11 +++++ .../table/components/table.component.ts | 21 +++++++- .../table/entities/column-properties.intf.ts | 8 ++++ showcase/src/app/demo-ui/components/index.ts | 1 + .../components/table-with-footer/index.ts | 1 + .../table-with-footer.component.html | 3 ++ .../table-with-footer.component.scss | 4 ++ .../table-with-footer.component.ts | 48 +++++++++++++++++++ showcase/src/app/demo-ui/demo-ui.module.ts | 2 + .../table/demo-table-page.component.html | 9 ++++ .../examples/table/with-footer/table.html | 3 ++ .../examples/table/with-footer/table.scss | 4 ++ .../examples/table/with-footer/table.ts | 38 +++++++++++++++ showcase/src/assets/translations/en.json | 4 ++ showcase/src/assets/translations/fr.json | 4 ++ showcase/src/assets/translations/nl.json | 4 ++ 18 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 showcase/src/app/demo-ui/components/table-with-footer/index.ts create mode 100644 showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.html create mode 100644 showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.scss create mode 100644 showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.ts create mode 100644 showcase/src/assets/examples/table/with-footer/table.html create mode 100644 showcase/src/assets/examples/table/with-footer/table.scss create mode 100644 showcase/src/assets/examples/table/with-footer/table.ts diff --git a/packages/stark-ui/src/modules/table/components/column.component.html b/packages/stark-ui/src/modules/table/components/column.component.html index 73ffb93cca..e91e1419a4 100644 --- a/packages/stark-ui/src/modules/table/components/column.component.html +++ b/packages/stark-ui/src/modules/table/components/column.component.html @@ -39,4 +39,9 @@ *ngTemplateOutlet="columnTemplate; context: { $implicit: { rowData: rowItem, displayedValue: getDisplayedValue(rowItem) } }" > + + + {{ footerValue!.toString() | translate }} + + diff --git a/packages/stark-ui/src/modules/table/components/column.component.ts b/packages/stark-ui/src/modules/table/components/column.component.ts index aeb398d606..a56d233efa 100644 --- a/packages/stark-ui/src/modules/table/components/column.component.ts +++ b/packages/stark-ui/src/modules/table/components/column.component.ts @@ -130,6 +130,27 @@ export class StarkTableColumnComponent extends AbstractStarkUiComponent implemen */ private _headerLabel?: string; + /** + * Value to be shown as the column's footer. + */ + @Input() + public set footerValue(value: string | number | undefined) { + this._footerValue = value; + } + + /** + * Returns the footer value of the column if it's specified. + */ + public get footerValue(): string | number | undefined { + return this._footerValue; + } + + /** + * @ignore + * @internal + */ + private _footerValue?: string | number; + /** * Whether the column is sortable or not. Default: true */ diff --git a/packages/stark-ui/src/modules/table/components/table.component.html b/packages/stark-ui/src/modules/table/components/table.component.html index fc0dbac98e..704c379f8f 100644 --- a/packages/stark-ui/src/modules/table/components/table.component.html +++ b/packages/stark-ui/src/modules/table/components/table.component.html @@ -98,17 +98,24 @@ [checked]="selection?.isSelected(row)" > + + + {{ getRowIndex(row) }} + + + + + + + diff --git a/packages/stark-ui/src/modules/table/components/table.component.ts b/packages/stark-ui/src/modules/table/components/table.component.ts index 6622f623bc..c7534c07a2 100644 --- a/packages/stark-ui/src/modules/table/components/table.component.ts +++ b/packages/stark-ui/src/modules/table/components/table.component.ts @@ -45,6 +45,7 @@ import { AbstractStarkUiComponent } from "../../../common/classes/abstract-compo import { StarkPaginateEvent, StarkPaginationComponent, StarkPaginationConfig } from "../../pagination/components"; import { StarkMinimapComponentMode, StarkMinimapItemProperties } from "../../minimap/components"; import find from "lodash-es/find"; +import findIndex from "lodash-es/findIndex"; /** * Name of the component @@ -68,6 +69,8 @@ const DEFAULT_COLUMN_PROPERTIES: Partial = { isVisible: true }; +// FIXME: refactor the template of this component function to reduce its cyclomatic complexity +/* tslint:disable:template-cyclomatic-complexity */ /** * Component to display array data in a table layout. */ @@ -82,16 +85,22 @@ const DEFAULT_COLUMN_PROPERTIES: Partial = { class: componentName } }) -/* tslint:enable */ export class StarkTableComponent extends AbstractStarkUiComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { /** * Array of {@link StarkTableColumnProperties} objects which define the columns of the data table. */ @Input() public set columnProperties(input: StarkTableColumnProperties[]) { + this.isFooterEnabled = + findIndex( + input || [], + (column: StarkTableColumnProperties) => typeof column.footerValue !== "undefined" && column.footerValue !== "" + ) > -1; + this._columnProperties = (input || []).map((properties: StarkTableColumnProperties) => ({ ...DEFAULT_COLUMN_PROPERTIES, - ...properties + ...properties, + footerValue: this.isFooterEnabled ? properties.footerValue || "" : undefined })); if (this.dataSource) { @@ -424,6 +433,14 @@ export class StarkTableComponent extends AbstractStarkUiComponent implements OnI */ public isFixedHeaderEnabled = false; + /** + * Whether the footer is enabled. + * Default: if there is no footer defined here and in any other column, then it won't be displayed. + * Otherwise, if at least one of the other columns defines a footer, + * then the footer of this column will be displayed as empty + */ + public isFooterEnabled = false; + /** * Whether the current sorting is done on multiple columns */ diff --git a/packages/stark-ui/src/modules/table/entities/column-properties.intf.ts b/packages/stark-ui/src/modules/table/entities/column-properties.intf.ts index 6335ec64ef..fe93107042 100644 --- a/packages/stark-ui/src/modules/table/entities/column-properties.intf.ts +++ b/packages/stark-ui/src/modules/table/entities/column-properties.intf.ts @@ -60,6 +60,14 @@ export interface StarkTableColumnProperties { */ label?: string; + /** + * Value to be shown as the column's footer. + * Default: if there is no footer defined here and in any other column, + * then it won't be displayed. Otherwise, if at least one of the other columns defines a footer, + * then the footer of this column will be displayed as empty + */ + footerValue?: string | number; + /** * Name of the property that will be the source of the column. */ diff --git a/showcase/src/app/demo-ui/components/index.ts b/showcase/src/app/demo-ui/components/index.ts index 5a21c15c35..1d16b14e70 100644 --- a/showcase/src/app/demo-ui/components/index.ts +++ b/showcase/src/app/demo-ui/components/index.ts @@ -6,3 +6,4 @@ export * from "./table-with-transcluded-action-bar"; export * from "./table-with-fixed-header"; export * from "./table-with-custom-styling"; export * from "./table-with-fixed-actions"; +export * from "./table-with-footer"; diff --git a/showcase/src/app/demo-ui/components/table-with-footer/index.ts b/showcase/src/app/demo-ui/components/table-with-footer/index.ts new file mode 100644 index 0000000000..a69ef39785 --- /dev/null +++ b/showcase/src/app/demo-ui/components/table-with-footer/index.ts @@ -0,0 +1 @@ +export * from "./table-with-footer.component"; diff --git a/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.html b/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.html new file mode 100644 index 0000000000..6b798a8f81 --- /dev/null +++ b/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.html @@ -0,0 +1,3 @@ + +

SHOWCASE.DEMO.TABLE.WITH_FOOTER

+
diff --git a/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.scss b/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.scss new file mode 100644 index 0000000000..19930c0e07 --- /dev/null +++ b/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.scss @@ -0,0 +1,4 @@ +// Row class +tr.mat-footer-row { + font-weight: bold; +} diff --git a/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.ts b/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.ts new file mode 100644 index 0000000000..68488dfd98 --- /dev/null +++ b/showcase/src/app/demo-ui/components/table-with-footer/table-with-footer.component.ts @@ -0,0 +1,48 @@ +import { Component, ViewEncapsulation } from "@angular/core"; +import { StarkPaginationConfig, StarkTableColumnProperties, StarkTableFilter } from "@nationalbankbelgium/stark-ui"; + +const DUMMY_DATA: object[] = [ + { id: 1, cost: 12, description: "number one" }, + { id: 10, cost: 23, description: "second description" }, + { id: 12, cost: 5, description: "the third description" }, + { id: 2, cost: 33, description: "description number four" }, + { id: 23, cost: 54, description: "fifth description" }, + { id: 222, cost: 3, description: "the sixth description" }, + { id: 112, cost: 7, description: "seventh description" }, + { id: 232, cost: 24, description: "description number eight" }, + { id: 154, cost: 35, description: "the ninth description" }, + { id: 27, cost: 10, description: "description number ten" }, + { id: 86, cost: 21, description: "eleventh description" }, + { id: 44, cost: 6, description: "the twelfth description" } +]; + +@Component({ + selector: "showcase-table-with-footer", + templateUrl: "./table-with-footer.component.html", + styleUrls: ["./table-with-footer.component.scss"], + /* tslint:disable-next-line:use-view-encapsulation */ + encapsulation: ViewEncapsulation.None // Important +}) +export class TableWithFooterComponent { + public data: object[] = DUMMY_DATA; + public paginationConfig: StarkPaginationConfig = { + itemsPerPage: 10 + }; + + public columns: StarkTableColumnProperties[] = [ + { name: "id", label: "Id", footerValue: "SHOWCASE.DEMO.TABLE.FOOTER.TOTAL" }, + { + name: "cost", + label: "SHOWCASE.DEMO.TABLE.LABELS.TITLE", + footerValue: this.getTotal() + }, + { name: "description", label: "SHOWCASE.DEMO.TABLE.LABELS.DESCRIPTION" } + ]; + + public filter: StarkTableFilter = { globalFilterPresent: false, columns: [] }; + + /** Gets the total cost of all products. */ + private getTotal(): number { + return DUMMY_DATA.map((obj: any) => obj.cost).reduce((acc: number, value: number) => acc + value, 0); + } +} diff --git a/showcase/src/app/demo-ui/demo-ui.module.ts b/showcase/src/app/demo-ui/demo-ui.module.ts index fa2231025a..6922294472 100644 --- a/showcase/src/app/demo-ui/demo-ui.module.ts +++ b/showcase/src/app/demo-ui/demo-ui.module.ts @@ -73,6 +73,7 @@ import { TableWithCustomStylingComponent, TableWithFixedActionsComponent, TableWithFixedHeaderComponent, + TableWithFooterComponent, TableWithSelectionComponent, TableWithTranscludedActionBarComponent } from "./components"; @@ -146,6 +147,7 @@ import { TableWithCustomActionsComponent, TableWithTranscludedActionBarComponent, TableWithFixedHeaderComponent, + TableWithFooterComponent, TableWithCustomStylingComponent, TableWithFixedActionsComponent, DemoToastPageComponent, diff --git a/showcase/src/app/demo-ui/pages/table/demo-table-page.component.html b/showcase/src/app/demo-ui/pages/table/demo-table-page.component.html index 82b952ea22..e320be5ce3 100644 --- a/showcase/src/app/demo-ui/pages/table/demo-table-page.component.html +++ b/showcase/src/app/demo-ui/pages/table/demo-table-page.component.html @@ -72,5 +72,14 @@

SHOWCASE.DEMO.SHARED.EXAMPLE_VIEWER_LIST

> + + + + diff --git a/showcase/src/assets/examples/table/with-footer/table.html b/showcase/src/assets/examples/table/with-footer/table.html new file mode 100644 index 0000000000..279938373f --- /dev/null +++ b/showcase/src/assets/examples/table/with-footer/table.html @@ -0,0 +1,3 @@ + +

Table with footer

+
diff --git a/showcase/src/assets/examples/table/with-footer/table.scss b/showcase/src/assets/examples/table/with-footer/table.scss new file mode 100644 index 0000000000..19930c0e07 --- /dev/null +++ b/showcase/src/assets/examples/table/with-footer/table.scss @@ -0,0 +1,4 @@ +// Row class +tr.mat-footer-row { + font-weight: bold; +} diff --git a/showcase/src/assets/examples/table/with-footer/table.ts b/showcase/src/assets/examples/table/with-footer/table.ts new file mode 100644 index 0000000000..8f12c9465d --- /dev/null +++ b/showcase/src/assets/examples/table/with-footer/table.ts @@ -0,0 +1,38 @@ +import { Component, ViewEncapsulation } from "@angular/core"; +import { StarkPaginationConfig, StarkTableColumnProperties, StarkTableFilter } from "@nationalbankbelgium/stark-ui"; + +const DUMMY_DATA: object[] = [ + { id: 1, cost: 12, description: "number one" }, + /* ... */ + { id: 44, cost: 6, description: "the twelfth description" } +]; + +@Component({ + selector: "showcase-table-with-footer", + templateUrl: "./table-with-footer.component.html", + styleUrls: ["./table-with-footer.component.scss"], + encapsulation: ViewEncapsulation.None // Important +}) +export class TableWithFooterComponent { + public data: object[] = DUMMY_DATA; + public paginationConfig: StarkPaginationConfig = { + itemsPerPage: 10 + }; + + public columns: StarkTableColumnProperties[] = [ + { name: "id", label: "Id", footerValue: "SHOWCASE.DEMO.TABLE.FOOTER.TOTAL" }, + { + name: "cost", + label: "SHOWCASE.DEMO.TABLE.LABELS.TITLE", + footerValue: this.getTotal() + }, + { name: "description", label: "SHOWCASE.DEMO.TABLE.LABELS.DESCRIPTION" } + ]; + + public filter: StarkTableFilter = { globalFilterPresent: false, columns: [] }; + + /** Gets the total cost of all products. */ + private getTotal(): number { + return DUMMY_DATA.map((obj: any) => obj.cost).reduce((acc: number, value: number) => acc + value, 0); + } +} diff --git a/showcase/src/assets/translations/en.json b/showcase/src/assets/translations/en.json index cc57cd5ce1..04e5bd366b 100644 --- a/showcase/src/assets/translations/en.json +++ b/showcase/src/assets/translations/en.json @@ -328,11 +328,15 @@ "DESCRIPTION": "Description", "EXTRA_INFO": "Extra info" }, + "FOOTER": { + "TOTAL": "Total" + }, "REGULAR": "Regular Table", "WITH_SELECTION": "Table with selection", "WITH_ITEMS_PER_PAGE_SELECTOR": "Table with the selector of items per page to display", "WITH_CUSTOM_ACTIONS": "Table with custom actions", "WITH_FIXED_HEADER": "Table with fixed header", + "WITH_FOOTER": "Table with footer", "WITH_TRANSCLUDED_ACTION_BAR": "Table with transcluded Action bar", "WITH_CUSTOM_STYLING": "Table with custom styling", "WITH_FIXED_ACTIONS": "Table with fixed row actions", diff --git a/showcase/src/assets/translations/fr.json b/showcase/src/assets/translations/fr.json index 8a7cbfec9f..8918413ed4 100644 --- a/showcase/src/assets/translations/fr.json +++ b/showcase/src/assets/translations/fr.json @@ -328,11 +328,15 @@ "DESCRIPTION": "Description", "EXTRA_INFO": "Information supplémentaire" }, + "FOOTER": { + "TOTAL": "Total" + }, "REGULAR": "Table régulière", "WITH_SELECTION": "Table avec sélection", "WITH_ITEMS_PER_PAGE_SELECTOR": "Table avec le sélecteur du nombre d'éléments par page à afficher", "WITH_CUSTOM_ACTIONS": "Table avec actions personalisé", "WITH_FIXED_HEADER": "Table avec en-tête fixe", + "WITH_FOOTER": "Table avec footer", "WITH_TRANSCLUDED_ACTION_BAR": "Table avec Action Bar 'transcluded'", "WITH_CUSTOM_STYLING": "Table avec mise en page personnalisé", "WITH_FIXED_ACTIONS": "Table avec actions de ligne fixes", diff --git a/showcase/src/assets/translations/nl.json b/showcase/src/assets/translations/nl.json index 691ede95c5..75e528c2d9 100644 --- a/showcase/src/assets/translations/nl.json +++ b/showcase/src/assets/translations/nl.json @@ -328,11 +328,15 @@ "DESCRIPTION": "Omschrijving", "EXTRA_INFO": "Extra informatie" }, + "FOOTER": { + "TOTAL": "Totaal" + }, "REGULAR": "Normale tabel", "WITH_SELECTION": "Tabel met selectie", "WITH_ITEMS_PER_PAGE_SELECTOR": "Tabel met de selector van items per pagina om weer te geven", "WITH_CUSTOM_ACTIONS": "Tabel met aangepaste acties", "WITH_FIXED_HEADER": "Tabel met vaste header", + "WITH_FOOTER": "Tabel met footer", "WITH_TRANSCLUDED_ACTION_BAR": "Tabel met 'transcluded' Action Bar", "WITH_CUSTOM_STYLING": "Tabel met aangepaste opmaak", "WITH_FIXED_ACTIONS": "Tabel met vaste rijacties",