diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2020-11-16 22:31:47 +0100 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2020-11-16 22:31:47 +0100 |
| commit | b7196aea72ccea2a26ad9c7cac1fac0da80b6d26 (patch) | |
| tree | 436efe47ff8eb636177c320fbc889a9cb4092cdb /grid/src | |
| parent | a4bf3451bbfc6292f8d33d5241d693251d5a0d01 (diff) | |
| download | web-components-b7196aea72ccea2a26ad9c7cac1fac0da80b6d26.tar.xz web-components-b7196aea72ccea2a26ad9c7cac1fac0da80b6d26.zip | |
add search
Diffstat (limited to 'grid/src')
| -rw-r--r-- | grid/src/grid.ts | 143 |
1 files changed, 103 insertions, 40 deletions
diff --git a/grid/src/grid.ts b/grid/src/grid.ts index 5fcf252..0953268 100644 --- a/grid/src/grid.ts +++ b/grid/src/grid.ts @@ -1,3 +1,36 @@ +import * as JsSearch from "js-search"; + +interface GridProps { + id?: string; + debug?: boolean; + data: Array<Object>; + columns: Array<GridColumn>; + pageSize?: number; + search?: SearchConfiguration; +} + +interface GridConfiguration { + id: string; + debug: boolean; + data: Array<Object>; + columns: Array<GridColumn>; + pageSize: number; + search: SearchConfiguration; +} + +interface SearchConfiguration { + dataIds: Array<string>; +} + +interface GridColumn { + dataId?: string; + columnName: string | Function; + cellValue?: string | Function | Element; + width?: string; + maxWidth?: string; + minWidth?: string; +} + export default class Grid { private readonly canRender: boolean; private readonly defaultOptions: GridConfiguration = { @@ -6,10 +39,13 @@ export default class Grid { columns: [], data: [], pageSize: 0, + search: { + dataIds: [], + }, }; private configuration: GridConfiguration; private domElement: Element; - private currentPage: number = 0; + public currentPage: number = 0; constructor(props: GridProps) { this.setOptions(props); @@ -31,6 +67,7 @@ export default class Grid { this.configuration.id = props.id ?? this.defaultOptions.id; this.configuration.debug = props.debug ?? this.defaultOptions.debug; this.configuration.pageSize = props.pageSize ?? this.defaultOptions.pageSize; + this.configuration.search = props.search ?? this.defaultOptions.search; } private validateOptions(): void { @@ -42,20 +79,15 @@ export default class Grid { } } - private navigate(pageNumber) { - const maxPage = Math.ceil(this.configuration.data.length / this.configuration.pageSize - 1); - if (this.configuration.pageSize <= 0 || pageNumber < 0 || pageNumber === this.currentPage || pageNumber > maxPage) return; - this.log("Navigating to page: " + pageNumber); - const skipCount = this.configuration.pageSize * pageNumber; - const endIndex = - this.configuration.data.length < skipCount + this.configuration.pageSize - ? this.configuration.data.length - : skipCount + this.configuration.pageSize; - this.renderBody(this.configuration.data.slice(skipCount, endIndex)); - this.currentPage = pageNumber; + private renderCurrentPageIndicator(): void { + if (this.configuration.pageSize <= 0) return; + this.domElement.querySelectorAll(".pagination .page-item").forEach((el) => { + if (el.getAttribute("data-page-number") == this.currentPage.toString()) el.classList.add("active"); + else el.classList.remove("active"); + }); } - private renderPaginator() { + private renderPaginator(): void { if (this.configuration.pageSize === 0) return; const nav = document.createElement("nav"); nav.className = "float-right user-select-none"; @@ -74,6 +106,7 @@ export default class Grid { for (let i = 0; i < this.configuration.data.length / this.configuration.pageSize; i++) { const item = document.createElement("li"); item.className = "page-item"; + item.dataset.pageNumber = i.toString(); item.onclick = () => this.navigate(i); const link = document.createElement("span"); link.className = "page-link"; @@ -119,7 +152,7 @@ export default class Grid { wrapper.appendChild(row); } - private renderBody(data: Array<any> = null): void { + private renderBody(data: Array<Object> = null): void { const wrapper = this.domElement.querySelector("table tbody"); wrapper.innerHTML = ""; let items = data ?? this.configuration.data; @@ -131,6 +164,9 @@ export default class Grid { row.dataset.id = item[this.configuration.id]; for (const val of this.configuration.columns) { const cell = document.createElement("td"); + if (val.width) cell.style.width = val.width; + if (val.maxWidth) cell.style.maxWidth = val.maxWidth; + if (val.minWidth) cell.style.minWidth = val.minWidth; if (typeof val.dataId === "string" && val.dataId.length > 0) { val.cellValue = item[val.dataId]; } @@ -167,6 +203,50 @@ export default class Grid { console.log("Grid Debug: " + message); } + private renderSearch() { + if (this.configuration.search.dataIds.length < 1) return; + const wrapper = document.createElement("div"); + const searchInput = document.createElement("input"); + searchInput.type = "text"; + searchInput.className = "form-control"; + searchInput.placeholder = "Søk"; + searchInput.oninput = () => this.search(searchInput.value); + wrapper.appendChild(searchInput); + this.domElement.appendChild(wrapper); + } + + private searchIndex: JsSearch.Search; + + private populateSearchIndex() { + if (this.configuration.search.dataIds.length < 1) return; + this.searchIndex = new JsSearch.Search("id"); + this.searchIndex.indexStrategy = new JsSearch.ExactWordIndexStrategy(); + this.configuration.search.dataIds.forEach((id) => this.searchIndex.addIndex(id)); + this.searchIndex.addDocuments(this.configuration.data); + console.log(this.searchIndex); + } + + public search(query: string): void { + if (this.configuration.search.dataIds.length < 1) return; + let result = this.searchIndex.search(query); + if (result.length === 0) result = this.configuration.data; + this.renderBody(result); + } + + public navigate(pageNumber): void { + const maxPage = Math.ceil(this.configuration.data.length / this.configuration.pageSize - 1); + if (this.configuration.pageSize <= 0 || pageNumber < 0 || pageNumber === this.currentPage || pageNumber > maxPage) return; + this.log("Navigating to page: " + pageNumber); + const skipCount = this.configuration.pageSize * pageNumber; + const endIndex = + this.configuration.data.length < skipCount + this.configuration.pageSize + ? this.configuration.data.length + : skipCount + this.configuration.pageSize; + this.renderBody(this.configuration.data.slice(skipCount, endIndex)); + this.currentPage = pageNumber; + this.renderCurrentPageIndicator(); + } + public removeByID(id: string): void { const itemIndex = this.configuration.data.findIndex((c) => c[this.configuration.id] === id); if (itemIndex !== -1) { @@ -177,19 +257,24 @@ export default class Grid { } } - public refreshData() { - this.renderBody(); + public refreshData(data?: Array<Object>) { + this.renderPaginator(); + this.navigate(0); + this.renderBody(data); } public render(el: Element): void { if (this.canRender) { - this.log("Grid starting render", true); + this.log("Grid starting render"); this.domElement = el; + this.renderSearch(); + this.populateSearchIndex(); this.renderWrapper(); this.renderHead(); this.renderBody(); this.renderPaginator(); - this.log("Grid was rendered", true); + this.renderCurrentPageIndicator(); + this.log("Grid was rendered"); } else { throw new GridError("render is not allowed due to invalid props"); } @@ -220,25 +305,3 @@ function isGridColumn(val: GridColumn | string): val is GridColumn { return false; } } - -interface GridProps { - id?: string; - debug?: boolean; - data: Array<any>; - columns: Array<GridColumn>; - pageSize?: number; -} - -interface GridConfiguration { - id: string; - debug: boolean; - data: Array<any>; - columns: Array<GridColumn>; - pageSize: number; -} - -interface GridColumn { - dataId?: string; - columnName: string | Function; - cellValue?: string | Function | Element; -} |
