From bd3037153814ed2ae4d433f72c0c17f8f1a679ec Mon Sep 17 00:00:00 2001 From: christophercr Date: Mon, 23 Jul 2018 12:28:34 +0200 Subject: [PATCH] feat(stark-ui): implement Pagination component. Integrate pagination in Table component ISSUES CLOSED: #539 --- packages/stark-ui/src/modules.ts | 5 +- packages/stark-ui/src/modules/pagination.ts | 2 + .../src/modules/pagination/components.ts | 2 + .../components/_pagination.component.scss | 318 +++++ .../components/pagination-config.intf.ts | 52 + .../components/pagination.component.html | 125 ++ .../components/pagination.component.spec.ts | 1084 +++++++++++++++++ .../components/pagination.component.ts | 430 +++++++ .../modules/pagination/pagination.module.ts | 30 + .../table/components/column.component.html | 1 + .../table/components/table.component.html | 49 +- .../table/components/table.component.ts | 55 +- .../src/modules/table/table.module.ts | 8 +- showcase/src/app/app.module.ts | 5 +- showcase/src/app/app.routes.ts | 6 +- showcase/src/app/demo/demo.module.ts | 30 +- .../app/demo/table/demo-table.component.html | 49 + ...mponent.scss => demo-table.component.scss} | 0 ...e.component.ts => demo-table.component.ts} | 28 +- showcase/src/app/demo/table/index.ts | 2 +- .../src/app/demo/table/table.component.html | 31 - showcase/src/styles/_stark-styles.scss | 1 + 22 files changed, 2225 insertions(+), 88 deletions(-) create mode 100644 packages/stark-ui/src/modules/pagination.ts create mode 100644 packages/stark-ui/src/modules/pagination/components.ts create mode 100644 packages/stark-ui/src/modules/pagination/components/_pagination.component.scss create mode 100644 packages/stark-ui/src/modules/pagination/components/pagination-config.intf.ts create mode 100644 packages/stark-ui/src/modules/pagination/components/pagination.component.html create mode 100644 packages/stark-ui/src/modules/pagination/components/pagination.component.spec.ts create mode 100644 packages/stark-ui/src/modules/pagination/components/pagination.component.ts create mode 100644 packages/stark-ui/src/modules/pagination/pagination.module.ts create mode 100644 showcase/src/app/demo/table/demo-table.component.html rename showcase/src/app/demo/table/{table.component.scss => demo-table.component.scss} (100%) rename showcase/src/app/demo/table/{table.component.ts => demo-table.component.ts} (85%) delete mode 100644 showcase/src/app/demo/table/table.component.html diff --git a/packages/stark-ui/src/modules.ts b/packages/stark-ui/src/modules.ts index ad3b86e3bd..8d964dd0b9 100644 --- a/packages/stark-ui/src/modules.ts +++ b/packages/stark-ui/src/modules.ts @@ -1,12 +1,13 @@ export * from "./modules/action-bar"; export * from "./modules/app-logo"; export * from "./modules/app-logout"; -export * from "./modules/breadcrumb"; export * from "./modules/app-sidebar"; -export * from "./modules/keyboard-directives"; +export * from "./modules/breadcrumb"; export * from "./modules/date-picker"; export * from "./modules/date-range-picker"; export * from "./modules/dropdown"; +export * from "./modules/keyboard-directives"; +export * from "./modules/pagination"; export * from "./modules/pretty-print"; export * from "./modules/slider"; export * from "./modules/svg-view-box"; diff --git a/packages/stark-ui/src/modules/pagination.ts b/packages/stark-ui/src/modules/pagination.ts new file mode 100644 index 0000000000..be06e59348 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination.ts @@ -0,0 +1,2 @@ +export * from "./pagination/pagination.module"; +export * from "./pagination/components"; diff --git a/packages/stark-ui/src/modules/pagination/components.ts b/packages/stark-ui/src/modules/pagination/components.ts new file mode 100644 index 0000000000..82d047bd70 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components.ts @@ -0,0 +1,2 @@ +export * from "./components/pagination.component"; +export * from "./components/pagination-config.intf"; diff --git a/packages/stark-ui/src/modules/pagination/components/_pagination.component.scss b/packages/stark-ui/src/modules/pagination/components/_pagination.component.scss new file mode 100644 index 0000000000..3e36bcff22 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/_pagination.component.scss @@ -0,0 +1,318 @@ +/********** PAGINATION **********/ +/* stark: src/modules/pagination/components/_pagination.component.scss */ +.stark-pagination > div { + display: flex; + flex-flow: row nowrap; + width: auto; + margin: 0; + padding: 0; + & ul { + display: flex; + flex-flow: row nowrap; + width: auto; + list-style: none; + height: 100%; + max-height: 50px; + margin: 0; + padding: 0; + } + & .stark-dropdown, + & mat-select { + height: 100%; + } + & .previous, + & .next, + & .first-page, + & .last-page { + font-size: 16px; + font-weight: 400; + line-height: 20px; + & button.mat-icon-button { + width: auto; + height: 100%; + padding: 5px; + border: none; + border-radius: 2px; + /* background-color: rgba(255, 255, 255, .04);*/ + cursor: pointer; + } + & mat-icon { + width: 24px; + min-width: 24px; + height: 24px; + min-height: 24px; + } + } + & .pagination-items-per-page { + display: flex; + width: auto; + margin: 0; + padding: 0; + & mat-select-value { + min-width: 0; + min-height: 0; + padding: 13px 4px 0; + align-items: flex-start; + } + } + &.compact { + @media #{$desktop-query} { + & li { + background-color: transparent; + } + } + + @media #{$mobile-only-query} { + & li { + & a { + color: #000; + } + } + } + } + + @media #{$mobile-only-query} { + position: absolute; + top: 0; + right: 40px; + font-size: 16px; + line-height: 24px; + & mat-select:focus:not([disabled]) .mat-select-value { + border-bottom-color: transparent; + color: #fff; + } + + & li { + display: none; + &.active, + &.previous, + &.next { + display: block; + padding: 6px 0; + & a { + display: block; + line-height: 38px; + color: #fff; + } + } + } + + & .previous, + & .next { + & button[disabled="disabled"] mat-icon { + fill: rgba(255, 255, 255, 0.4); + } + } + + & .pagination-items-per-page { + & .mat-select-value { + color: #fff; + } + & mat-select span { + margin-right: 5px; + } + } + + & .pagination-enter-page { + display: none; + } + + & mat-select:focus:not([disabled]) * { + color: #fff !important; + } + } + + @media #{$tablet-query} { + position: relative; + float: right; + max-height: 48px; + border-radius: 2px; + display: inline-flex; + margin: 0; + padding: 0; + & li { + display: none; + align-items: center; + width: 30px; + } + & .previous, + & .next, + & .first-page, + & .last-page { + display: flex; + width: 40px; + } + & .previous, + & .next, + & .first-page, + & .last-page { + & button.mat-icon-button { + width: 40px; + padding: 7px 8px 6px; + border: none; + box-shadow: none; + outline: none; + &[disabled="disabled"] mat-icon { + outline: none; + fill: rgba(0, 0, 0, 0.14); + } + } + } + + & .previous { + margin-right: 1px; + } + + & .next { + margin-left: 1px; + } + + & .pagination-enter-page { + margin: 4px 24px 0 4px; + font-size: 12px; + flex: 0 0 auto; + & span { + color: $primary-dark-text-color; + } + & input { + display: inline-block; + margin-right: 4px; + width: 26px; + height: 24px; + padding: 4px; + border: solid 1px $divider-color; + border-radius: 2px; + font-size: 12px; + text-align: center; + } + } + + & .pagination-items-per-page { + & mat-select-value { + margin-top: 4px; + height: 24px; + padding: 4px; + border: solid 1px $divider-color; + border-radius: 2px; + font-size: 12px; + background: #fff; + align-items: center; + &:focus { + border: 0; + outline: dashed 1px #ccc; + } + & span:first-child { + padding-right: 3px; + } + } + } + } + + @media #{$desktop-query} { + max-height: 40px; + & li { + display: flex; + background-color: rgba(0, 0, 0, 0.02); + & a, + & span { + display: block; + width: 100%; + padding: 1px 0; + text-align: center; + color: rgba(0, 0, 0, 0.5); + cursor: pointer; + } + &.active a { + color: $md-primary; + } + } + & .mat-icon-button { + background-color: transparent; + } + & .previous { + margin-right: 0; + } + & .pagination { + margin-right: 24px; + } + & .next { + margin-left: 0; + } + } +} + +.stark-action-bar-pagination { + & .stark-pagination { + margin-right: 0; + } + & .mat-icon-button { + transform: translateY(-3px); + } + & .page-numbers { + display: none; + } +} + +.pagination-enter-page { + margin: 0; +} + +@media #{$desktop-query} { + .stark-pagination .page-numbers { + display: flex; + } +} + +/********** DENSE MODE **********/ +.dense-mode { + & .stark-pagination { + height: 24px; + overflow: hidden; + margin-right: 0; + & ul li button.mat-icon-button { + padding: 0; + } + & .pagination-items-per-page .mat-select-value { + margin-top: 0; + height: 14px; + } + } +} + +.stark-table .stark-table-action-bar { + & .stark-action-bar-pagination { + & li { + padding: 0 4px; + } + & .mat-icon-button { + transform: none; + margin: 0; + & mat-icon { + width: 20px; + height: 20px; + min-width: 20px; + min-height: 20px; + } + } + & .pagination-enter-page { + margin: 2px 0 0 0; + padding-right: 8px; + } + } +} + +.stark-table .stark-table-action-bar { + & .stark-action-bar-pagination { + & button:not([disabled]), + & button[disabled] { + background: 0; + border: none; + } + } +} + +.stark-pagination button[disabled] { + background-color: transparent; +} + +/* END stark: src/modules/pagination/components/_pagination.component.pcss */ diff --git a/packages/stark-ui/src/modules/pagination/components/pagination-config.intf.ts b/packages/stark-ui/src/modules/pagination/components/pagination-config.intf.ts new file mode 100644 index 0000000000..baf518eaf3 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination-config.intf.ts @@ -0,0 +1,52 @@ +/** + * Defines the config object to be used with the Pagination component. + */ +export interface StarkPaginationConfig { + /** + * If true, the component will be displayed in "extended" mode (an "extended-pagination" class is added to the element). + * Default: false + */ + isExtended?: boolean; + + /** + * Number of items displayed on each page. The number of available pages for pagination is calculated based on this number. + * Default: itemsPerPageOptions[0] + */ + itemsPerPage?: number; + + /** + * Available options for items per page dropdown. + * Default : [5,10,15] + */ + itemsPerPageOptions?: number[]; + + /** + * If false, then itemsPerPage dropdown will not be present. + * Default: true + */ + itemsPerPageIsPresent?: boolean; + + /** + * Current page index. + * Default: 0 + */ + page?: number; + + /** + * If false, then page nav bar will not be present. + * Default: true + */ + pageNavIsPresent?: boolean; + + /** + * f false, then input box for page selection will not be present. + * Default: true + */ + pageInputIsPresent?: boolean; + + /** + * Number of items being paged in order to calculate number of pages for pagination. + * Default: 0 + */ + totalItems?: number; +} diff --git a/packages/stark-ui/src/modules/pagination/components/pagination.component.html b/packages/stark-ui/src/modules/pagination/components/pagination.component.html new file mode 100644 index 0000000000..8a3395c73c --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination.component.html @@ -0,0 +1,125 @@ +
+ +
+ + {{ getTotalPages() }} +
+
+ +
+
+ +
+ +
diff --git a/packages/stark-ui/src/modules/pagination/components/pagination.component.spec.ts b/packages/stark-ui/src/modules/pagination/components/pagination.component.spec.ts new file mode 100644 index 0000000000..1ea3e3d386 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination.component.spec.ts @@ -0,0 +1,1084 @@ +import { async, ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { MatInputModule } from "@angular/material/input"; +import { MatMenuModule } from "@angular/material/menu"; +import { MatPaginatorModule } from "@angular/material/paginator"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { MatButtonModule } from "@angular/material/button"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { Component, DebugElement, NO_ERRORS_SCHEMA, ViewChild } from "@angular/core"; +import { By } from "@angular/platform-browser"; +import { TranslateModule } from "@ngx-translate/core"; +import { STARK_LOGGING_SERVICE } from "@nationalbankbelgium/stark-core"; +import { MockStarkLoggingService } from "@nationalbankbelgium/stark-core/testing"; +import { Observer } from "rxjs"; +import { StarkPaginateEvent, StarkPaginationComponent } from "./pagination.component"; +import { StarkPaginationConfig } from "./pagination-config.intf"; +import { StarkDropdownComponent, StarkDropdownModule } from "../../dropdown"; +import { StarkKeyboardDirectivesModule } from "../../keyboard-directives"; +import SpyObj = jasmine.SpyObj; +import createSpyObj = jasmine.createSpyObj; + +@Component({ + selector: `host-component`, + template: ` + + ` +}) +class TestHostComponent { + @ViewChild(StarkPaginationComponent) + public paginationComponent: StarkPaginationComponent; + + public htmlSuffixId: string; + public paginationConfig: StarkPaginationConfig; +} + +fdescribe("PaginationComponent", () => { + let hostComponent: TestHostComponent; + let hostFixture: ComponentFixture; + let component: StarkPaginationComponent; + + const paginationConfig: StarkPaginationConfig = { + page: 2, + itemsPerPage: 4, + itemsPerPageOptions: [4, 8, 12], + totalItems: 6, + isExtended: true + }; + + const assertPageNavSelection: Function = (paginationElement: DebugElement, selectedOption: string) => { + const pageNavElement: DebugElement = paginationElement.query(By.css("ul")); + const pageNavOptionElements: DebugElement[] = pageNavElement.queryAll(By.css("li")); + + for (const pageNavOption of pageNavOptionElements) { + if (pageNavOption.properties["value"] === selectedOption) { + expect(pageNavOption.classes["active"]).toBe(true); + } else { + expect(pageNavOption.classes["active"]).toBeFalsy(); // can be undefined or false + } + } + }; + + const changeInputValueAndPressEnter: Function = (rootElement: DebugElement, value: string) => { + const querySelector: string = "div.pagination-enter-page input"; + const pageSelectorInput: DebugElement = rootElement.query(By.css(querySelector)); + + (pageSelectorInput.nativeElement).value = value; + (pageSelectorInput.nativeElement).dispatchEvent(new Event("input")); + + const changeEvent: Event = document.createEvent("Event"); + changeEvent.initEvent("change", true, true); + pageSelectorInput.triggerEventHandler("change", changeEvent); + + const keypressEvent: Event = document.createEvent("Event"); + keypressEvent.initEvent("keypress", true, true); + keypressEvent["which"] = 13; + pageSelectorInput.triggerEventHandler("keypress", keypressEvent); + }; + + const assertPageInputSelection: Function = (rootElement: DebugElement, selectedOption: string) => { + const querySelector: string = "div.pagination-enter-page input"; + const pageSelectorInput: DebugElement = rootElement.query(By.css(querySelector)); + expect(pageSelectorInput.properties["value"].toString()).toBe(selectedOption); + }; + + beforeEach(async(() => { + return TestBed.configureTestingModule({ + imports: [ + FormsModule, + MatButtonModule, + MatInputModule, + MatMenuModule, + MatPaginatorModule, + MatTooltipModule, + NoopAnimationsModule, + TranslateModule.forRoot(), + StarkDropdownModule, + StarkKeyboardDirectivesModule + ], + declarations: [StarkPaginationComponent, TestHostComponent], + providers: [{ provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }], + schemas: [NO_ERRORS_SCHEMA] // to avoid errors due to "mat-icon" directive not known (which we don't want to add in these tests) + }).compileComponents(); + })); + + beforeEach(() => { + hostFixture = TestBed.createComponent(TestHostComponent); + hostComponent = hostFixture.componentInstance; + hostFixture.detectChanges(); + + component = hostComponent.paginationComponent; + }); + + describe("on initialization", () => { + it("should set internal component properties", () => { + expect(hostFixture).toBeDefined(); + expect(component).toBeDefined(); + + expect(component.logger).not.toBeNull(); + expect(component.logger).toBeDefined(); + }); + + it("should NOT have any inputs set", () => { + expect(component.htmlSuffixId).toBe("pagination"); + expect(component.mode).toBeUndefined(); + expect(component.paginationConfig).toBeDefined(); + }); + + it("should render the appropriate content in normal mode", () => { + hostComponent.paginationConfig = { + page: 2, + itemsPerPage: 4, + itemsPerPageOptions: [4, 8, 12], + totalItems: 10, + isExtended: false, + pageNavIsPresent: true, + pageInputIsPresent: true, + itemsPerPageIsPresent: true + }; + hostFixture.detectChanges(); + + const pageNavElement: DebugElement = hostFixture.debugElement.query(By.css("ul")); + expect(pageNavElement).toBeDefined(); + expect(pageNavElement.nativeElement.innerHTML).toContain('
  • elements to "0" instead of "..." + const morePagesElement: DebugElement = hostFixture.debugElement.query(By.css("li[value='0']")); + morePagesElement.triggerEventHandler("click", {}); + hostFixture.detectChanges(); + tick(); // since values are set on ngModel asynchronously (see https://github.com/angular/angular/issues/22606) + + assertPageNavSelection(hostFixture.debugElement.childNodes[0], "1"); + assertPageInputSelection(hostFixture.debugElement.childNodes[0], "1"); + })); + }); + + describe("on paginationConfig change", () => { + beforeEach(fakeAsync(() => { + hostComponent.paginationConfig = { ...paginationConfig, totalItems: 10 }; + hostFixture.detectChanges(); + tick(); // since values are set on ngModel asynchronously (see https://github.com/angular/angular/issues/22606) + })); + + it("should change pageNumbers if totalItems has changed", () => { + const previousPageNumbersLength: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + hostComponent.paginationConfig = { ...paginationConfig, totalItems: 13 }; + hostFixture.detectChanges(); + const currentPageNumbersElement: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + expect(currentPageNumbersElement).not.toEqual(previousPageNumbersLength); + }); + + it("should not change pageNumbers if totalItems has not changed", () => { + const previousPageNumbersLength: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + hostComponent.paginationConfig = { ...paginationConfig, totalItems: 10 }; + hostFixture.detectChanges(); + const currentPageNumbersElement: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + expect(currentPageNumbersElement).toEqual(previousPageNumbersLength); + }); + + it("should set current page to 1 when it is undefined in config", fakeAsync(() => { + assertPageNavSelection(hostFixture.debugElement.childNodes[0], "2"); + assertPageInputSelection(hostFixture.debugElement.childNodes[0], "2"); + + hostComponent.paginationConfig = { ...paginationConfig, page: undefined }; + hostFixture.detectChanges(); + tick(); // since values are set on ngModel asynchronously (see https://github.com/angular/angular/issues/22606) + + assertPageNavSelection(hostFixture.debugElement.childNodes[0], "1"); + assertPageInputSelection(hostFixture.debugElement.childNodes[0], "1"); + })); + }); +}); diff --git a/packages/stark-ui/src/modules/pagination/components/pagination.component.ts b/packages/stark-ui/src/modules/pagination/components/pagination.component.ts new file mode 100644 index 0000000000..35e4c3d104 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination.component.ts @@ -0,0 +1,430 @@ +"use strict"; + +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + HostBinding, + Inject, + Input, + OnChanges, + OnInit, + Output, + Renderer2, + SimpleChanges, + ViewEncapsulation +} from "@angular/core"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { StarkPaginationConfig } from "./pagination-config.intf"; +import { MatPaginator, MatPaginatorIntl, PageEvent } from "@angular/material/paginator"; + +const _isEqual: Function = require("lodash/isEqual"); + +const componentName: string = "stark-pagination"; + +export type StarkPaginationComponentMode = "compact"; + +export interface StarkPaginateEvent { + /** + * Current page after pagination + */ + page: number; + + /** + * Current number of items displayed per page + */ + itemsPerPage: number; +} + +/** + * Component to display pagination bar to be used with a collection of items. + * It extends the MatPaginator class from Angular Material so it can be integrated as well with the MatTable. + * {@link https://material.angular.io/components/paginator/api|MatPaginator} + */ +@Component({ + selector: "stark-pagination", + templateUrl: "./pagination.component.html", + encapsulation: ViewEncapsulation.None +}) +export class StarkPaginationComponent extends MatPaginator implements OnInit, OnChanges, AfterViewInit { + /** + * Adds class="stark-pagination" attribute on the host component + */ + @HostBinding("class") + public class: string = componentName; + + /** + * Suffix id given to items per page dropdown + * (items-per-page-) and pageSelector dropdown (page-selector-) + * Default: "pagination" + */ + @Input() + public htmlSuffixId?: string; + + /** + * Desired layout or flavour: + * - compact: Displayed in a compact mode. + * - default: basic implementation with everything + */ + @Input() + public mode?: StarkPaginationComponentMode; + + /** + * StarkPaginationConfig object containing main information for the pagination. + */ + @Input() + public paginationConfig: StarkPaginationConfig; + + /** + * Output event emitter that will emit the paginate event when the pagination changed. + */ + @Output() + public paginated: EventEmitter = new EventEmitter(); + + public get paginationInput(): number { + return this._paginationInput; + } + + public set paginationInput(newValue: number) { + // store the previous pagination input value in case the new one is not valid + // so it can be reverted to the previous value when that happens + if (this._paginationInput && (newValue > this.getTotalPages() || newValue === 0)) { + this.previousPaginationInput = this._paginationInput; + } + this._paginationInput = newValue; + } + + public _paginationInput: number; + public previousPaginationInput: number; + public previousPageIndex: number; + public pageNumbers: (string | number)[]; + + public constructor( + @Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService, + public element: ElementRef, + public renderer: Renderer2, + public cdRef: ChangeDetectorRef + ) { + // we don't use the MatPaginatorIntl service to translate the labels but it is needed for the MatPaginator base class + // see https://material.angular.io/components/paginator/api#services + super(new MatPaginatorIntl(), cdRef); + } + + /** + * Component lifecycle hook + */ + public ngOnInit(): void { + this.paginationConfig = this.normalizePaginationConfig(this.paginationConfig); + this.setMatPaginatorProperties(this.paginationConfig); + this.previousPageIndex = 0; + + this.htmlSuffixId = this.htmlSuffixId || "pagination"; + + this.setPageNumbers(); + + super.ngOnInit(); + this.logger.debug(componentName + ": controller initialized"); + } + + /** + * Component lifecycle hook + */ + public ngAfterViewInit(): void { + if (this.paginationConfig.isExtended) { + this.renderer.addClass(this.element.nativeElement, "extended-pagination"); + } + } + + /** + * Component lifecycle hook + */ + public ngOnChanges(changesObj: SimpleChanges): void { + if (changesObj["paginationConfig"]) { + // Set local variable to prevent shadow changes + const paginationConfigOriginalChange: StarkPaginationConfig = { ...this.paginationConfig }; + this.paginationConfig = this.normalizePaginationConfig(this.paginationConfig); + this.logger.debug(componentName + ": paginationConfig changed...", this.paginationConfig); + + // If normalization has changed the page or itemsPerPage, that means the paginationConfig is not the same in the pagination controller + // and in the parent controller. So pagination hast to trigger onPaginate callback to pass the new values. + if ( + typeof paginationConfigOriginalChange === "undefined" || + paginationConfigOriginalChange.page !== this.paginationConfig.page || + paginationConfigOriginalChange.itemsPerPage !== this.paginationConfig.itemsPerPage + ) { + this.onChangePagination(); + } else if ( + !_isEqual(paginationConfigOriginalChange, changesObj["paginationConfig"].previousValue) || + paginationConfigOriginalChange.totalItems !== this.paginationConfig.totalItems || + paginationConfigOriginalChange.itemsPerPageOptions !== this.paginationConfig.itemsPerPageOptions + ) { + this.setPageNumbers(); + } + this.paginationInput = this.paginationConfig.page; + } + } + + /** + * Creates a normalized paginationConfig to be used by this component. + * If the given config is undefined it will set totalItems only, otherwise it sets default values for the missing properties + */ + // FIXME: refactor this function to reduce its cognitive complexity + public normalizePaginationConfig(config: StarkPaginationConfig | undefined): StarkPaginationConfig { + let normalizedConfig: StarkPaginationConfig; + if (!config) { + // initialize paginationConfig to prevent errors in other functions depending on this config + normalizedConfig = { + totalItems: 0 + }; + this.logger.warn(componentName + ": No configuration defined. TotalItems set to 0 by default"); + } else { + normalizedConfig = { + itemsPerPageOptions: config.itemsPerPageOptions || [5, 10, 15], + itemsPerPage: config.itemsPerPage || (config.itemsPerPageOptions ? config.itemsPerPageOptions[0] : 5), + page: config.page || 1, + isExtended: config.isExtended !== undefined ? config.isExtended : false, + itemsPerPageIsPresent: config.itemsPerPageIsPresent !== undefined ? config.itemsPerPageIsPresent : true, + pageNavIsPresent: config.pageNavIsPresent !== undefined ? config.pageNavIsPresent : true, + pageInputIsPresent: config.pageInputIsPresent !== undefined ? config.pageInputIsPresent : true, + totalItems: config.totalItems !== undefined ? config.totalItems : 0 + }; + this.logger.debug(componentName + ": normalized pagination config: ", normalizedConfig); + } + + return normalizedConfig; + } + + /** + * Set the properties needed for the MatPaginator base class based on the given pagination configuration + * {@link https://material.angular.io/components/paginator/api#MatPaginator|MatPaginator API} + * @param config - The config object which be used to set the MatPaginator properties + */ + public setMatPaginatorProperties(config: StarkPaginationConfig): void { + // The set of provided page size options to display to the user. + this.pageSizeOptions = config.itemsPerPageOptions; + // Number of items to display on a page. By default set to 50. + this.pageSize = config.itemsPerPage; + // The zero-based page index of the displayed list of items. Defaulted to 0. + this.pageIndex = config.page - 1; // zero-based + // The length of the total number of items that are being paginated. Defaulted to 0. + this.length = config.totalItems; + } + + /** + * Check whether the given value is equal to zero (as number 0 or as string "0"). + */ + public isZero(numberToCheck: string | number): boolean { + return numberToCheck === 0 || numberToCheck === "0"; + } + + /** + * Check whether there is a page after the current one. + */ + public hasNext(): boolean { + return this.paginationConfig && this.paginationConfig.page < this.getTotalPages(); + } + + /** + * Check whether there is a page before the current one. + */ + public hasPrevious(): boolean { + return this.paginationConfig && this.paginationConfig.page > 1; + } + + /** + * Change page to first one. + */ + public goToFirst(): void { + if (this.hasPrevious()) { + this.goToPage(1); + } + } + + /** + * Change page to previous one. + */ + public goToPrevious(): void { + if (this.hasPrevious()) { + this.goToPage(this.paginationConfig.page - 1); + } + } + + /** + * Change page to next one. + */ + public goToNext(): void { + if (this.hasNext()) { + this.goToPage(this.paginationConfig.page + 1); + } + } + + /** + * Change page to last one. + */ + public goToLast(): void { + if (this.hasNext()) { + this.goToPage(this.getTotalPages()); + } + } + + /** + * Emit the stark paginate event and the MatPagination event. + * Then reload pageNumbers variable. + */ + public onChangePagination(): void { + if ( + this.paginationConfig && + // Check the types of page & itemsPerPage to be sure they are not undefined + typeof this.paginationConfig.page === "number" && + typeof this.paginationConfig.itemsPerPage === "number" + ) { + this.paginated.emit({ + page: this.paginationConfig.page, + itemsPerPage: this.paginationConfig.itemsPerPage + }); + + this.setMatPaginatorProperties(this.paginationConfig); + this.emitMatPaginationEvent(); + } + this.setPageNumbers(); + this.paginationInput = this.paginationConfig.page; + } + + /** + * Get total number of pages available based on itemsPerPage and totalItems. + */ + public getTotalPages(): number { + let calculatedTotalPages: number = 0; + if (this.paginationConfig) { + const itemsPerPage: number = this.isZero(this.paginationConfig.itemsPerPage) + ? 1 + : this.paginationConfig.itemsPerPage; + calculatedTotalPages = Math.ceil(this.paginationConfig.totalItems / itemsPerPage); + } + + if (calculatedTotalPages === 0) { + return 1; + } + return calculatedTotalPages; + } + + /** + * Set page to first then call onChangePagination function. + */ + public onChangeItemsPerPage(itemsPerPage: number): void { + this.paginationConfig.page = 1; + this.paginationConfig.itemsPerPage = itemsPerPage; + this.onChangePagination(); + } + + /** + * Set pageNumbers variable. + */ + // FIXME: refactor this function to reduce its cognitive complexity + public setPageNumbers(): void { + let min: number; + let max: number; + let i: number; + let j: number; + + const input: (string | number)[] = []; + + if (this.isCompactMode()) { + min = this.paginationConfig.page > 1 ? this.paginationConfig.page - 1 : 1; + max = min + 2; + + for (j = 0, i = min; i <= max && i <= this.getTotalPages(); i++, j++) { + input[j] = i; + } + } else { + // default mode: stark + min = 1; + max = this.getTotalPages(); + + if (max < 6) { + for (j = 0, i = min; i <= max; i++, j++) { + input[j] = i; + } + } else { + input[0] = min; + input[4] = max; + + if (this.paginationConfig.page === min + 2 || this.paginationConfig.page === min + 1) { + input[2] = min + 2; + } else if (this.paginationConfig.page === max - 2 || this.paginationConfig.page === max - 1) { + input[2] = max - 2; + } else if (this.paginationConfig.page === max || this.paginationConfig.page === min) { + input[2] = Math.ceil(max / 2); + } else { + input[2] = this.paginationConfig.page; + } + + if (input[2] - 1 === min + 1) { + input[1] = min + 1; + } else { + input[1] = "..."; + } + + if (input[2] + 1 === max - 1) { + input[3] = max - 1; + } else { + input[3] = "..."; + } + } + } + + this.pageNumbers = input; + } + + /** + * Change to the given page if it is different than "...". It calls onChangePagination afterwards. + */ + public goToPage(page: number | "..."): void { + if (page !== "...") { + this.previousPageIndex = this.paginationConfig.page; + this.paginationConfig.page = page; + this.onChangePagination(); + } + } + + public changePageOnEnter(): void { + const newPage: number = typeof this.paginationInput === "string" ? parseInt(this.paginationInput, 10) : this.paginationInput; + if (newPage <= this.getTotalPages() && newPage > 0) { + this.goToPage(newPage); + } else { + this.logger.warn(componentName + ": the page ", newPage, " does not exist"); + this.paginationInput = this.previousPaginationInput; // revert the pagination input value + } + } + + public getPageInputMaxDigits(): number { + return this.getTotalPages().toString().length; + } + + public isCompactMode(): boolean { + return typeof this.mode !== "undefined" && this.mode === "compact"; + } + + /** + * Emit the PageEvent according to the MatPaginator API + * {@link https://material.angular.io/components/paginator/api#PageEvent|MatPaginator PageEvent} + */ + public emitMatPaginationEvent(): void { + const pageEvent: PageEvent = { + pageIndex: this.pageIndex, + pageSize: this.pageSize, + length: this.length, + previousPageIndex: this.previousPageIndex + }; + this.page.emit(pageEvent); + } + + /** + * @ignore + */ + public trackPageNumberFn(_index: number): number { + return _index; + } +} diff --git a/packages/stark-ui/src/modules/pagination/pagination.module.ts b/packages/stark-ui/src/modules/pagination/pagination.module.ts new file mode 100644 index 0000000000..21b71c08dc --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/pagination.module.ts @@ -0,0 +1,30 @@ +import { NgModule } from "@angular/core"; +import { FormsModule } from "@angular/forms"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { MatIconModule } from "@angular/material/icon"; +import { MatInputModule } from "@angular/material/input"; +import { MatButtonModule } from "@angular/material/button"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { MatPaginatorModule } from "@angular/material/paginator"; +import { StarkPaginationComponent } from "./components"; +import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module"; +import { StarkKeyboardDirectivesModule } from "../keyboard-directives/keyboard-directives.module"; +import { StarkDropdownModule } from "../dropdown/dropdown.module"; + +@NgModule({ + declarations: [StarkPaginationComponent], + exports: [StarkPaginationComponent], + imports: [ + BrowserAnimationsModule, + FormsModule, + MatButtonModule, + MatIconModule, + MatInputModule, + MatPaginatorModule, + MatTooltipModule, + StarkKeyboardDirectivesModule, + StarkSvgViewBoxModule, + StarkDropdownModule + ] +}) +export class StarkPaginationModule {} 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 52c6118778..8e906f6078 100644 --- a/packages/stark-ui/src/modules/table/components/column.component.html +++ b/packages/stark-ui/src/modules/table/components/column.component.html @@ -1,5 +1,6 @@ +
    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 67d686a442..8d619dbe82 100644 --- a/packages/stark-ui/src/modules/table/components/table.component.html +++ b/packages/stark-ui/src/modules/table/components/table.component.html @@ -3,22 +3,29 @@
    - +
    - - + +
    @@ -31,17 +38,27 @@ - + {{ context.displayedValue }} @@ -51,7 +68,8 @@ - + @@ -59,5 +77,8 @@
    - + - +
    - + +
    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 b9bb419183..f0b32f4674 100644 --- a/packages/stark-ui/src/modules/table/components/table.component.ts +++ b/packages/stark-ui/src/modules/table/components/table.component.ts @@ -18,9 +18,9 @@ import { ViewEncapsulation } from "@angular/core"; import { MatDialog, MatDialogRef } from "@angular/material/dialog"; -import { MatPaginator } from "@angular/material/paginator"; import { MatColumnDef, MatTable, MatTableDataSource } from "@angular/material/table"; import { SelectionModel } from "@angular/cdk/collections"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; import { StarkTableColumnComponent, StarkTableColumnSortingDirection } from "./column.component"; import { StarkSortingRule, StarkTableMultisortDialogComponent, StarkTableMultisortDialogData } from "./dialogs/multisort.component"; @@ -28,7 +28,8 @@ import { StarkActionBarConfig } from "../../action-bar/components/action-bar-con import { StarkAction } from "../../action-bar/components/action.intf"; import { StarkTableColumnProperties } from "./column-properties.intf"; import { StarkTableFilter } from "./table-filter.intf"; -import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { StarkPaginationConfig, StarkPaginationComponent } from "../../pagination/components"; +import { StarkPaginateEvent } from "../../pagination/components/pagination.component"; /** * Name of the component @@ -37,7 +38,7 @@ const componentName: string = "stark-table"; /* tslint:disable:enforce-component-selector */ @Component({ - selector: componentName, + selector: "stark-table", templateUrl: "./table.component.html", encapsulation: ViewEncapsulation.None }) @@ -47,7 +48,13 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI * Adds class="stark-table" attribute on the host component */ @HostBinding("class") - public class: string = "stark-table"; + public class: string = componentName; + + /** + * HTML id of the table + */ + @Input() + public htmlId: string; /** * Data that will be display inside your table. @@ -85,6 +92,12 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI @Input() public paginate: boolean = false; + /** + * + */ + @Input() + public paginationConfig: StarkPaginationConfig; + /** * Allows multiple row selection. Setting the attribute to "true" or empty will enable this feature. */ @@ -121,6 +134,20 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI @Output() public filterChanged: EventEmitter = new EventEmitter(); + /** + * Callback function to be called when the pagination changes. Two parameters + * will be passed to the callback function: + * -- page (number) + * -- itemsPerPage (number) + * + * When you declare it in html tags you have to declare it like 'on-paginate="yourFunction(page,itemsPerPage)"' + * If no callback function is passed, the data will be paginated automatically by the component. + * + * When set onPaginate, these attributes are required : totalItems + */ + @Output() + public paginationChanged: EventEmitter = new EventEmitter(); + /** * Reference to the MatTable embedded in this component */ @@ -130,8 +157,8 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI /** * Reference to the MatPaginator embedded in this component */ - @ViewChild(MatPaginator) - public paginator: MatPaginator; + @ViewChild(StarkPaginationComponent) + public starkPaginator: StarkPaginationComponent; /** * Columns added automatically by this component according to the columnProperties input @@ -284,7 +311,6 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI // using the internal prop from mat-table to get the custom column definitions (no other way for now) const oldColumns: Set = this.table["_customColumnDefs"]; oldColumns.forEach((oldColumn: MatColumnDef) => { - this.logger.debug("CCR==========> removing oldColumns value", oldColumn.name); this.table.removeColumnDef(oldColumn); // removing column also from the displayed columns (such array should match the dataSource!) this.displayedColumns.splice(this.displayedColumns.findIndex((column: string) => column === oldColumn.name), 1); @@ -337,7 +363,20 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI */ private initializeDataSource(): void { this.dataSource = new MatTableDataSource(this.data); - this.dataSource.paginator = this.paginator; + + // if there are observers subscribed to the StarkPagination event, it means that the developer will take care of the pagination + // so we just re-emit the event from the Stark Pagination component (online mode) + if (this.paginationChanged.observers.length > 0) { + this.starkPaginator.paginated.subscribe((paginateEvent: StarkPaginateEvent) => { + this.paginationChanged.emit(paginateEvent); + }); + } else { + // if there are no observers, then the data will be paginated internally in the MatTable via the Stark paginator event (offline mode) + this.dataSource.paginator = this.starkPaginator; + } + + this.starkPaginator.emitMatPaginationEvent(); + this.dataSource.filterPredicate = (rowData: any, globalFilter: string) => { const matchFilter: boolean[] = []; diff --git a/packages/stark-ui/src/modules/table/table.module.ts b/packages/stark-ui/src/modules/table/table.module.ts index b03d6d02dc..207291aea6 100644 --- a/packages/stark-ui/src/modules/table/table.module.ts +++ b/packages/stark-ui/src/modules/table/table.module.ts @@ -6,17 +6,16 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; import { MatDialogModule } from "@angular/material/dialog"; import { MatIconModule } from "@angular/material/icon"; import { MatInputModule } from "@angular/material/input"; -import { MatListModule } from "@angular/material/list"; import { MatMenuModule } from "@angular/material/menu"; -import { MatPaginatorModule } from "@angular/material/paginator"; import { MatSelectModule } from "@angular/material/select"; import { MatSortModule } from "@angular/material/sort"; import { MatTableModule } from "@angular/material/table"; import { MatTooltipModule } from "@angular/material/tooltip"; +import { TranslateModule } from "@ngx-translate/core"; import { StarkTableComponent, StarkTableColumnComponent } from "./components"; import { StarkTableMultisortDialogComponent } from "./components/dialogs/multisort.component"; -import { TranslateModule } from "@ngx-translate/core"; import { StarkActionBarModule } from "../action-bar/action-bar.module"; +import { StarkPaginationModule } from "../pagination/pagination.module"; import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module"; @NgModule({ @@ -31,15 +30,14 @@ import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module"; MatDialogModule, MatIconModule, MatInputModule, - MatListModule, MatMenuModule, - MatPaginatorModule, MatSelectModule, MatSortModule, MatTableModule, MatTooltipModule, TranslateModule, StarkActionBarModule, + StarkPaginationModule, StarkSvgViewBoxModule ] }) diff --git a/showcase/src/app/app.module.ts b/showcase/src/app/app.module.ts index c22bc20d31..b30c5d3f69 100644 --- a/showcase/src/app/app.module.ts +++ b/showcase/src/app/app.module.ts @@ -10,16 +10,15 @@ import { EffectsModule } from "@ngrx/effects"; import { storeFreeze } from "ngrx-store-freeze"; import { storeLogger } from "ngrx-store-logger"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; -import { MatIconRegistry } from "@angular/material"; +import { MatIconRegistry, MatIconModule } from "@angular/material/icon"; import { MatButtonModule } from "@angular/material/button"; import { MatCardModule } from "@angular/material/card"; import { MatCheckboxModule } from "@angular/material/checkbox"; -import { MatIconModule } from "@angular/material/icon"; import { MatListModule } from "@angular/material/list"; import { MatSidenavModule } from "@angular/material/sidenav"; import { MatTooltipModule } from "@angular/material/tooltip"; -import { SharedModule } from "./shared/shared.module"; import { DateAdapter } from "@angular/material/core"; +import { SharedModule } from "./shared/shared.module"; import { STARK_APP_CONFIG, diff --git a/showcase/src/app/app.routes.ts b/showcase/src/app/app.routes.ts index 3a1cb4d250..300b745d74 100644 --- a/showcase/src/app/app.routes.ts +++ b/showcase/src/app/app.routes.ts @@ -12,7 +12,7 @@ import { LogoutComponent, DemoPrettyPrintComponent, SliderComponent, - TableComponent + DemoTableComponent } from "./demo"; import { HomeComponent } from "./home"; import { NoContentComponent } from "./no-content"; @@ -27,6 +27,7 @@ export const APP_STATES: Ng2StateDeclaration[] = [ { name: "demo-button", url: "/demo/button", component: ButtonComponent }, { name: "demo-date-picker", url: "/demo/date-picker", component: DatePickerComponent }, { name: "demo-date-range-picker", url: "/demo/date-range-picker", component: DateRangePickerComponent }, + { name: "demo-dropdown", url: "/demo/dropdown", component: DemoDropdownComponent }, { name: "stark-header", url: "/demo/stark-header", component: HeaderComponent }, { name: "demo-example-viewer", url: "/demo/example-viewer", component: ExampleViewerComponent }, { name: "demo-keyboard-directives", url: "/demo/keyboard-directives", component: KeyboardDirectivesComponent }, @@ -34,7 +35,6 @@ export const APP_STATES: Ng2StateDeclaration[] = [ { name: "demo-pretty-print", url: "/demo/pretty-print", component: DemoPrettyPrintComponent }, { name: "demo-slider", url: "/demo/slider", component: SliderComponent }, { name: "demo-sidebar", url: "/demo/sidebar", component: DemoSidebarComponent }, - { name: "demo-table", url: "/demo/table", component: TableComponent }, - { name: "demo-dropdown", url: "/demo/dropdown", component: DemoDropdownComponent }, + { name: "demo-table", url: "/demo/table", component: DemoTableComponent }, { name: "otherwise", url: "/otherwise", component: NoContentComponent } ]; diff --git a/showcase/src/app/demo/demo.module.ts b/showcase/src/app/demo/demo.module.ts index cbbc3b1574..b26f08717b 100644 --- a/showcase/src/app/demo/demo.module.ts +++ b/showcase/src/app/demo/demo.module.ts @@ -1,17 +1,16 @@ -import { - MatButtonModule, - MatCardModule, - MatCheckboxModule, - MatIconModule, - MatTabsModule, - MatTooltipModule, - MatSnackBarModule, - MatFormFieldModule, - MatInputModule -} from "@angular/material"; -import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; import { FormsModule } from "@angular/forms"; +import { MAT_DATE_FORMATS } from "@angular/material/core"; +import { MatCheckboxModule } from "@angular/material/checkbox"; +import { MatButtonModule } from "@angular/material/button"; +import { MatCardModule } from "@angular/material/card"; +import { MatIconModule } from "@angular/material/icon"; +import { MatTabsModule } from "@angular/material/tabs"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { MatSnackBarModule } from "@angular/material/snack-bar"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatInputModule } from "@angular/material/input"; import { TranslateModule } from "@ngx-translate/core"; import { ActionBarComponent } from "./action-bar/action-bar.component"; import { DemoBreadcrumbComponent } from "./breadcrumb/breadcrumb.component"; @@ -26,7 +25,7 @@ import { KeyboardDirectivesComponent } from "./keyboard-directives/keyboard-dire import { LogoutComponent } from "./logout/logout.component"; import { DemoPrettyPrintComponent } from "./pretty-print/demo-pretty-print.component"; import { SliderComponent } from "./slider/slider.component"; -import { TableComponent } from "./table/table.component"; +import { DemoTableComponent } from "./table/demo-table.component"; import { SharedModule } from "../shared/shared.module"; import { STARK_DATE_FORMATS, @@ -42,7 +41,6 @@ import { StarkSvgViewBoxModule, StarkTableModule } from "@nationalbankbelgium/stark-ui"; -import { MAT_DATE_FORMATS } from "@angular/material/core"; @NgModule({ imports: [ @@ -89,7 +87,7 @@ import { MAT_DATE_FORMATS } from "@angular/material/core"; DemoSidebarComponent, ExampleViewerComponent, KeyboardDirectivesComponent, - TableComponent + DemoTableComponent ], exports: [ ActionBarComponent, @@ -104,7 +102,7 @@ import { MAT_DATE_FORMATS } from "@angular/material/core"; LogoutComponent, DemoPrettyPrintComponent, SliderComponent, - TableComponent + DemoTableComponent ], providers: [{ provide: MAT_DATE_FORMATS, useValue: STARK_DATE_FORMATS }] }) diff --git a/showcase/src/app/demo/table/demo-table.component.html b/showcase/src/app/demo/table/demo-table.component.html new file mode 100644 index 0000000000..66964907a6 --- /dev/null +++ b/showcase/src/app/demo/table/demo-table.component.html @@ -0,0 +1,49 @@ + + +

    Table with regular action bar

    +
    +
    + + + +

    Table with alternative action bar

    +
    +
    + + + +
    +
    +

    Table with transcluded action bar

    + +
    +
    +
    +
    diff --git a/showcase/src/app/demo/table/table.component.scss b/showcase/src/app/demo/table/demo-table.component.scss similarity index 100% rename from showcase/src/app/demo/table/table.component.scss rename to showcase/src/app/demo/table/demo-table.component.scss diff --git a/showcase/src/app/demo/table/table.component.ts b/showcase/src/app/demo/table/demo-table.component.ts similarity index 85% rename from showcase/src/app/demo/table/table.component.ts rename to showcase/src/app/demo/table/demo-table.component.ts index 6e2f6a4343..54a9fba492 100644 --- a/showcase/src/app/demo/table/table.component.ts +++ b/showcase/src/app/demo/table/demo-table.component.ts @@ -1,14 +1,20 @@ import { Component, Inject, OnInit, ViewEncapsulation } from "@angular/core"; -import { StarkActionBarConfig, StarkTableColumnProperties, StarkTableFilter, StarkAction } from "@nationalbankbelgium/stark-ui"; +import { + StarkActionBarConfig, + StarkPaginationConfig, + StarkTableColumnProperties, + StarkTableFilter, + StarkAction +} from "@nationalbankbelgium/stark-ui"; import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; @Component({ - selector: "showcase-demo-table", - styleUrls: ["./table.component.scss"], - templateUrl: "./table.component.html", + selector: "demo-table", + styleUrls: ["./demo-table.component.scss"], + templateUrl: "./demo-table.component.html", encapsulation: ViewEncapsulation.None //Here to add a shadow inside the table, we will fix that when we take care of #509 }) -export class TableComponent implements OnInit { +export class DemoTableComponent implements OnInit { public getTitle = (data: any): string => { return "~" + data.title.label; }; @@ -27,6 +33,9 @@ export class TableComponent implements OnInit { public columnsProperties: StarkTableColumnProperties[]; public customTableActions: StarkAction[]; public tableRowsActionBarConfig: StarkActionBarConfig; + public paginationConfig1: StarkPaginationConfig; + public paginationConfig2: StarkPaginationConfig; + public paginationConfig3: StarkPaginationConfig; public columns: any[]; public orderProperties: string[]; public filter: StarkTableFilter; @@ -175,6 +184,15 @@ export class TableComponent implements OnInit { columns: [] }; + this.paginationConfig1 = { + totalItems: this.dummyData.length, + page: 1, + itemsPerPage: 10, + itemsPerPageOptions: [10, 12, 15, 18, 20, 25, 50, 100] + }; + this.paginationConfig2 = { ...this.paginationConfig1, itemsPerPage: 4, itemsPerPageOptions: [2, 4, 6, 8, 10] }; + this.paginationConfig3 = { ...this.paginationConfig1, itemsPerPage: 2, itemsPerPageOptions: [2, 4, 6, 8, 10], isExtended: true }; + this.tableRowsActionBarConfig = { actions: [ { diff --git a/showcase/src/app/demo/table/index.ts b/showcase/src/app/demo/table/index.ts index 4f364c859f..5f5ca4a13e 100644 --- a/showcase/src/app/demo/table/index.ts +++ b/showcase/src/app/demo/table/index.ts @@ -1 +1 @@ -export * from "./table.component"; +export * from "./demo-table.component"; diff --git a/showcase/src/app/demo/table/table.component.html b/showcase/src/app/demo/table/table.component.html deleted file mode 100644 index b4aa0baf67..0000000000 --- a/showcase/src/app/demo/table/table.component.html +++ /dev/null @@ -1,31 +0,0 @@ - - -

    Table with regular action bar

    -
    -
    - - - -

    Table with alternative action bar

    -
    -
    - - - -
    -
    -

    Table with transcluded action bar

    - -
    -
    -
    -
    \ No newline at end of file diff --git a/showcase/src/styles/_stark-styles.scss b/showcase/src/styles/_stark-styles.scss index 48ba3c752e..f4cb812e9e 100644 --- a/showcase/src/styles/_stark-styles.scss +++ b/showcase/src/styles/_stark-styles.scss @@ -14,6 +14,7 @@ IMPORTANT: Stark styles are provided as SCSS styles so they should be imported i @import "~@nationalbankbelgium/stark-ui/src/modules/breadcrumb/components/breadcrumb.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/date-range-picker/components/date-range-picker.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/slider/components/slider-theme"; +@import "~@nationalbankbelgium/stark-ui/src/modules/pagination/components/pagination.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/pretty-print/components/pretty-print.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/table/components/table.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/table/components/dialogs/multisort.component";