diff options
| -rw-r--r-- | grid/src/grid.ts | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/grid/src/grid.ts b/grid/src/grid.ts index 4623dda..3f59614 100644 --- a/grid/src/grid.ts +++ b/grid/src/grid.ts @@ -7,6 +7,7 @@ interface GridProps { columns: Array<GridColumn>; pageSize?: number; search?: SearchConfiguration; + tableClassName?: string; } interface GridConfiguration { @@ -16,13 +17,15 @@ interface GridConfiguration { columns: Array<GridColumn>; pageSize: number; search: SearchConfiguration; + tableClassName: string; } interface SearchConfiguration { - dataIds: Array<string>; + dataIds: Array<string | Array<string>>; } + interface GridColumn { - dataId?: string; + dataId?: string | Array<string>; columnName: string | Function; cellValue?: string | Function | Element; width?: string; @@ -34,18 +37,19 @@ export default class Grid { private readonly canRender: boolean; private readonly defaultOptions: GridConfiguration = { id: "id", - debug: true, + debug: false, columns: [], data: [], pageSize: 0, + tableClassName: "table", search: { dataIds: [], }, }; private configuration: GridConfiguration; private domElement: Element; - public currentPage: number = 0; private searchIndex: JsSearch.Search; + public currentPage: number = 0; constructor(props: GridProps) { this.setOptions(props); @@ -67,6 +71,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.tableClassName = props.tableClassName ?? this.defaultOptions.tableClassName; this.configuration.search = props.search ?? this.defaultOptions.search; } @@ -88,7 +93,7 @@ export default class Grid { } private renderPaginator(): void { - if (this.configuration.pageSize === 0) return; + if (this.configuration.pageSize === 0 || this.configuration.data.length < this.configuration.pageSize) return; const nav = document.createElement("nav"); nav.className = "float-right user-select-none"; const ul = document.createElement("ul"); @@ -134,7 +139,7 @@ export default class Grid { const wrapper = document.createElement("table"); const thead = document.createElement("thead"); const tbody = document.createElement("tbody"); - wrapper.className = "table"; + wrapper.className = this.configuration.tableClassName; wrapper.appendChild(thead); wrapper.appendChild(tbody); this.domElement.appendChild(wrapper); @@ -152,8 +157,26 @@ export default class Grid { wrapper.appendChild(row); } + // https://github.com/bvaughn/js-search/blob/master/source/getNestedFieldValue.js + private getNestedFieldValue<T>(object: Object, path: Array<string>): T { + path = path || []; + object = object || {}; + + let value = object; + + // walk down the property path + for (let i = 0; i < path.length; i++) { + value = value[path[i]]; + if (value == null) { + return null; + } + } + + return value as T; + } + private renderBody(data: Array<Object> = null, isSearchResult: boolean = false): void { - let wrapper = this.domElement.querySelector("table tbody"); + let wrapper: Element; if (isSearchResult) { this.domElement.querySelector("table tbody:not(.search-results)").classList.add("d-none"); this.domElement.querySelector("table tbody.search-results").classList.remove("d-none"); @@ -170,14 +193,22 @@ export default class Grid { } for (const item of items) { const row = document.createElement("tr"); + // @ts-ignore 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]; + if (val.dataId !== undefined && val.dataId.length > 0) { + if (Array.isArray(val.dataId)) { + // @ts-ignore + val.cellValue = val.dataId; + this.log(val.dataId); + } else { + // @ts-ignore + val.cellValue = item[val.dataId]; + } } cell.className = "text-break"; @@ -189,6 +220,8 @@ export default class Grid { const computed = val.cellValue(item); if (computed instanceof Element) cell.appendChild(computed); else if (typeof computed === "string" || typeof computed === "number") cell.innerText = computed as string; + } else if (Array.isArray(val.cellValue)) { + cell.innerText = this.getNestedFieldValue(item, val.cellValue); } row.appendChild(cell); } @@ -234,11 +267,10 @@ export default class Grid { private populateSearchIndex() { if (this.configuration.search.dataIds.length < 1) return; - this.searchIndex = new JsSearch.Search("id"); + this.searchIndex = new JsSearch.Search(this.configuration.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 { @@ -251,7 +283,7 @@ export default class Grid { } } - public navigate(pageNumber): void { + public navigate(pageNumber: number): 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); @@ -266,6 +298,7 @@ export default class Grid { } public removeByID(id: string): void { + // @ts-ignore const itemIndex = this.configuration.data.findIndex((c) => c[this.configuration.id] === id); if (itemIndex !== -1) { delete this.configuration.data[itemIndex]; @@ -275,10 +308,12 @@ export default class Grid { } } - public refreshData(data?: Array<Object>) { + public refresh(data?: Array<Object>) { this.renderPaginator(); this.navigate(0); - this.renderBody(data); + if (data !== undefined) this.configuration.data = data; + this.renderBody(); + this.populateSearchIndex(); } public render(el: Element): void { |
