diff --git a/.gitignore b/.gitignore index 2d45d27..5754d02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -/dist /tmp /node_modules /.idea /typings -npm-debug.log \ No newline at end of file +npm-debug.log +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md index 370776d..6a11384 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -## Angular 2 Data Table +## Angular 4 Data Table -A simple Angular 2 data table, with built-in solutions for features including: +This is fork of package [https://github.com/ggmod/angular-2-data-table] (https://github.com/ggmod/angular-2-data-table) + +A simple Angular 4 data table, with built-in solutions for features including: * pagination * sorting @@ -13,11 +15,24 @@ The component can be used not just with local data, but remote resources too: fo The templates use bootstrap CSS class names, so the component requires a bootstrap .css file to be present in the application using it. -Check out the [demo](https://ggmod.github.io/angular-2-data-table-demo) and its [code](https://github.com/ggmod/angular-2-data-table-demo) for examples of how to use it. +Check out the [demo](https://ggmod.github.io/angular-2-data-table-demo) and its [code](https://github.com/MIt9/angular-4-data-table-demo) for examples of how to use it. + +Demo for pagination with seperate page numbers will be added soon ## Installing: -`npm install angular-2-data-table --save` +`npm install angular-4-data-table --save` + +## Production (Minification) +Some times this can cause problems. +To fix it use import like this + +`import { DataTableModule } from 'angular-4-data-table';` + +and for production build use +`ng build --prod --aot=false` + ### Added numerical pagination support with 2 next and previous links + #### Licensing MIT License diff --git a/package.json b/package.json index 570f02c..c3e875c 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,42 @@ { - "name": "angular-2-data-table", - "version": "0.1.2", - "description": "An Angular 2 data table, with pagination, sorting, expandable rows etc.", + "name": "angular-4-data-table", + "version": "0.4.6", + "description": "An Angular 4 data table, with pagination, sorting, expandable rows etc.", "keywords": [ "angular", - "angular2", - "Angular 2", + "angular4", + "Angular 4", "ng2", "datatable", "data-table", "data table", "pagination" ], - "main": "dist/index.js", - "typings": "dist/index.d.ts", + "main": "src/index.ts", + "typings": "src/index.ts", "scripts": { - "build": "rm -rf dist/* && tsc", - "serve": "rm -rf dist/ && tsc -w", - "prepublish": "npm run build" }, "repository": { "type": "git", - "url": "git://git@github.com/ggmod/angular-2-data-table.git" + "url": "git+https://github.com/MIt9/angular-4-data-table.git" }, - "peerDependencies": { - "@angular/core": "^2.0.0" - }, - "author": "ggmod ", + "author": "Dmitrii Bilukha (http://donsamogon.com)", "license": "MIT", - "devDependencies": { - "@angular/common": "^2.0.0", - "@angular/core": "^2.0.0", - "@angular/forms": "^2.0.0", - "rxjs": "^5.0.0-beta.12", - "typescript": "^2.0.2" - } + "devDependencies": {}, + "dependencies": { + "@angular/core": "^4.0.0", + "@angular/common": "^4.0.1", + "@angular/forms": "^4.0.1", + "@angular/platform-browser": "^4.0.1", + "@types/node": "~6.0.60", + "rxjs": "^5.1.0", + "ts-node": "~2.0.0", + "typescript": "2.1.5", + "zone.js": "^0.8.12" + }, + "false": {}, + "bugs": { + "url": "https://github.com/MIt9/angular-4-data-table/issues" + }, + "homepage": "https://github.com/MIt9/angular-4-data-table#readme" } diff --git a/src/components/column.component.ts b/src/components/column.component.ts index 0abb1af..9b34b8c 100644 --- a/src/components/column.component.ts +++ b/src/components/column.component.ts @@ -1,6 +1,6 @@ import { Directive, Input, ContentChild, OnInit } from '@angular/core'; import { DataTableRow } from './row.component'; -import { CellCallback } from './types'; +import { CellCallback } from '../types/cell-callback.type'; @Directive({ diff --git a/src/components/header.component.ts b/src/components/header.component.ts index 5ba988e..3807325 100644 --- a/src/components/header.component.ts +++ b/src/components/header.component.ts @@ -5,6 +5,7 @@ import { HEADER_STYLE } from "./header.style"; @Component({ + moduleId: module.id +'', selector: 'data-table-header', template: HEADER_TEMPLATE, styles: [HEADER_STYLE], diff --git a/src/components/header.template.ts b/src/components/header.template.ts index b299a86..5bdc0fd 100644 --- a/src/components/header.template.ts +++ b/src/components/header.template.ts @@ -3,11 +3,13 @@ export const HEADER_TEMPLATE = `

@@ -40,4 +42,4 @@ export const HEADER_TEMPLATE = `
-`; \ No newline at end of file +`; diff --git a/src/components/pagination.component.ts b/src/components/pagination.component.ts index 4850be8..2c59fb9 100644 --- a/src/components/pagination.component.ts +++ b/src/components/pagination.component.ts @@ -1,17 +1,24 @@ -import { Component, Inject, forwardRef } from '@angular/core'; -import { DataTable } from './table.component'; -import { PAGINATION_TEMPLATE } from './pagination.template'; -import { PAGINATION_STYLE } from "./pagination.style"; +import {Component, Inject, forwardRef, Input} from '@angular/core'; +import {DataTable} from './table.component'; +import {PAGINATION_TEMPLATE} from './pagination.template'; +import {PAGINATION_STYLE} from "./pagination.style"; @Component({ - selector: 'data-table-pagination', - template: PAGINATION_TEMPLATE, - styles: [PAGINATION_STYLE] + moduleId: module.id +'', + selector: 'data-table-pagination', + template: PAGINATION_TEMPLATE, + styles: [PAGINATION_STYLE] }) export class DataTablePagination { - constructor(@Inject(forwardRef(() => DataTable)) public dataTable: DataTable) {} + @Input() show_range = false; + @Input() show_limit = false; + @Input() show_input = false; + @Input() show_numbers = true; + + constructor(@Inject(forwardRef(() => DataTable)) public dataTable: DataTable) { + } pageBack() { this.dataTable.offset -= Math.min(this.dataTable.limit, this.dataTable.offset); @@ -48,4 +55,29 @@ export class DataTablePagination { set page(value) { this.dataTable.page = Number(value); } + + createPageRange(number, page): any[] { + const displayedPage = 3; + let items: number[] = []; + if (number > 1) { + let maxPage = number; + let minPage = 1; + if (page === 1 && maxPage >= displayedPage) { + maxPage = 3; + } else if (page > 1 && maxPage > page + 1) { + minPage = page - 1; + maxPage = page + 1; + } else if (page > 2 && maxPage > page) { + minPage = page - 1; + maxPage = page + 1; + } else if (page > 2 && maxPage === page) { + minPage = page - 2; + maxPage = page; + } + for (let i = minPage; i <= maxPage; i++) { + items.push(i); + } + } + return items; + } } diff --git a/src/components/pagination.style.ts b/src/components/pagination.style.ts index 1fdb87d..34355eb 100644 --- a/src/components/pagination.style.ts +++ b/src/components/pagination.style.ts @@ -2,6 +2,8 @@ export const PAGINATION_STYLE = ` .pagination-box { position: relative; margin-top: -10px; + display: block; + height: 30px; } .pagination-range { margin-top: 7px; @@ -21,12 +23,13 @@ export const PAGINATION_STYLE = ` margin-right: 25px; display: inline-table; width: 150px; + float: left; } .pagination-pages { display: inline-block; } .pagination-page { - width: 110px; + width: 102px; display: inline-table; } .pagination-box button { diff --git a/src/components/pagination.template.ts b/src/components/pagination.template.ts index 65824fb..1ba3a32 100644 --- a/src/components/pagination.template.ts +++ b/src/components/pagination.template.ts @@ -1,6 +1,6 @@ export const PAGINATION_TEMPLATE = `
-
+
{{dataTable.translations.paginationRange}}: - @@ -9,7 +9,7 @@ export const PAGINATION_TEMPLATE = `
-
+
{{dataTable.translations.paginationLimit}}:
-
+
-
+
+
+ +
diff --git a/src/components/row.component.ts b/src/components/row.component.ts index 96da1c8..bce4008 100644 --- a/src/components/row.component.ts +++ b/src/components/row.component.ts @@ -7,6 +7,7 @@ import { ROW_STYLE } from "./row.style"; @Component({ + moduleId: module.id +'', selector: '[dataTableRow]', template: ROW_TEMPLATE, styles: [ROW_STYLE] @@ -56,5 +57,5 @@ export class DataTableRow implements OnDestroy { this.selected = false; } - private _this = this; // FIXME is there no template keyword for this in angular 2? + public _this = this; // FIXME is there no template keyword for this in angular 2? } diff --git a/src/components/row.template.ts b/src/components/row.template.ts index 7e881ea..17b0353 100644 --- a/src/components/row.template.ts +++ b/src/components/row.template.ts @@ -9,9 +9,11 @@ export const ROW_TEMPLATE = ` (dblclick)="dataTable.rowDoubleClicked(_this, $event)" (click)="dataTable.rowClicked(_this, $event)" > - - - + +
+ +
@@ -28,4 +30,4 @@ export const ROW_TEMPLATE = `
-`; \ No newline at end of file +`; diff --git a/src/components/table.component.ts b/src/components/table.component.ts index e78cdf7..e389b1a 100644 --- a/src/components/table.component.ts +++ b/src/components/table.component.ts @@ -1,361 +1,368 @@ import { - Component, Input, Output, EventEmitter, ContentChildren, QueryList, - TemplateRef, ContentChild, ViewChildren, OnInit + Component, Input, Output, EventEmitter, ContentChildren, QueryList, + TemplateRef, ContentChild, ViewChildren, OnInit } from '@angular/core'; import { DataTableColumn } from './column.component'; import { DataTableRow } from './row.component'; -import { DataTableParams } from './types'; -import { RowCallback } from './types'; -import { DataTableTranslations, defaultTranslations } from './types'; +import { DataTableParams } from '../types/data-table-params.type'; +import { RowCallback } from '../types/row-callback.type'; +import { DataTableTranslations } from '../types/data-table-translations.type'; +import { defaultTranslations } from '../types/default-translations.type'; import { drag } from '../utils/drag'; import { TABLE_TEMPLATE } from './table.template'; import { TABLE_STYLE } from "./table.style"; - - @Component({ - selector: 'data-table', - template: TABLE_TEMPLATE, - styles: [TABLE_STYLE] + moduleId: module.id +'', + selector: 'data-table', + template: TABLE_TEMPLATE, + styles: [TABLE_STYLE] }) export class DataTable implements DataTableParams, OnInit { - private _items: any[] = []; - - @Input() get items() { - return this._items; - } - - set items(items: any[]) { - this._items = items; - this._onReloadFinished(); - } - - @Input() itemCount: number; - - // UI components: - - @ContentChildren(DataTableColumn) columns: QueryList; - @ViewChildren(DataTableRow) rows: QueryList; - @ContentChild('dataTableExpand') expandTemplate: TemplateRef; - - // One-time optional bindings with default values: - - @Input() headerTitle: string; - @Input() header = true; - @Input() pagination = true; - @Input() indexColumn = true; - @Input() indexColumnHeader = ''; - @Input() rowColors: RowCallback; - @Input() rowTooltip: RowCallback; - @Input() selectColumn = false; - @Input() multiSelect = true; - @Input() substituteRows = true; - @Input() expandableRows = false; - @Input() translations: DataTableTranslations = defaultTranslations; - @Input() selectOnRowClick = false; - @Input() autoReload = true; - @Input() showReloading = false; - - // UI state without input: - - indexColumnVisible: boolean; - selectColumnVisible: boolean; - expandColumnVisible: boolean; - - // UI state: visible ge/set for the outside with @Input for one-time initial values - - private _sortBy: string; - private _sortAsc = true; - - private _offset = 0; - private _limit = 10; - - @Input() - get sortBy() { - return this._sortBy; - } - - set sortBy(value) { - this._sortBy = value; - this._triggerReload(); - } - - @Input() - get sortAsc() { - return this._sortAsc; - } - - set sortAsc(value) { - this._sortAsc = value; - this._triggerReload(); - } - - @Input() - get offset() { - return this._offset; - } - - set offset(value) { - this._offset = value; - this._triggerReload(); - } - - @Input() - get limit() { - return this._limit; - } - - set limit(value) { - this._limit = value; - this._triggerReload(); - } - - // calculated property: - - @Input() - get page() { - return Math.floor(this.offset / this.limit) + 1; - } - - set page(value) { - this.offset = (value - 1) * this.limit; - } - - get lastPage() { - return Math.ceil(this.itemCount / this.limit); - } - - // setting multiple observable properties simultaneously - - sort(sortBy: string, asc: boolean) { - this.sortBy = sortBy; - this.sortAsc = asc; - } - - // init - - ngOnInit() { - this._initDefaultValues(); - this._initDefaultClickEvents(); - this._updateDisplayParams(); - - if (this.autoReload && this._scheduledReload == null) { - this.reloadItems(); - } - } - - private _initDefaultValues() { - this.indexColumnVisible = this.indexColumn; - this.selectColumnVisible = this.selectColumn; - this.expandColumnVisible = this.expandableRows; - } - - private _initDefaultClickEvents() { - this.headerClick.subscribe(tableEvent => this.sortColumn(tableEvent.column)); - if (this.selectOnRowClick) { - this.rowClick.subscribe(tableEvent => tableEvent.row.selected = !tableEvent.row.selected); - } - } - - // Reloading: - - _reloading = false; - - get reloading() { - return this._reloading; - } - - @Output() reload = new EventEmitter(); - - reloadItems() { - this._reloading = true; - this.reload.emit(this._getRemoteParameters()); - } - - private _onReloadFinished() { - this._updateDisplayParams(); - - this._selectAllCheckbox = false; - this._reloading = false; - } - - _displayParams = {}; // params of the last finished reload - - get displayParams() { - return this._displayParams; - } - - _updateDisplayParams() { - this._displayParams = { - sortBy: this.sortBy, - sortAsc: this.sortAsc, - offset: this.offset, - limit: this.limit - }; - } - - _scheduledReload = null; - - // for avoiding cascading reloads if multiple params are set at once: - _triggerReload() { - if (this._scheduledReload) { - clearTimeout(this._scheduledReload); - } - this._scheduledReload = setTimeout(() => { - this.reloadItems(); - }); - } - - // event handlers: - - @Output() rowClick = new EventEmitter(); - @Output() rowDoubleClick = new EventEmitter(); - @Output() headerClick = new EventEmitter(); - @Output() cellClick = new EventEmitter(); - - private rowClicked(row: DataTableRow, event) { - this.rowClick.emit({ row, event }); - } - - private rowDoubleClicked(row: DataTableRow, event) { - this.rowDoubleClick.emit({ row, event }); - } - - private headerClicked(column: DataTableColumn, event: MouseEvent) { - if (!this._resizeInProgress) { - this.headerClick.emit({ column, event }); - } else { - this._resizeInProgress = false; // this is because I can't prevent click from mousup of the drag end - } - } - - private cellClicked(column: DataTableColumn, row: DataTableRow, event: MouseEvent) { - this.cellClick.emit({ row, column, event }); - } - - // functions: - - private _getRemoteParameters(): DataTableParams { - let params = {}; - - if (this.sortBy) { - params.sortBy = this.sortBy; - params.sortAsc = this.sortAsc; - } - if (this.pagination) { - params.offset = this.offset; - params.limit = this.limit; - } - return params; - } - - private sortColumn(column: DataTableColumn) { - if (column.sortable) { - let ascending = this.sortBy === column.property ? !this.sortAsc : true; - this.sort(column.property, ascending); - } - } - - get columnCount() { - let count = 0; - count += this.indexColumnVisible ? 1 : 0; - count += this.selectColumnVisible ? 1 : 0; - count += this.expandColumnVisible ? 1 : 0; - this.columns.toArray().forEach(column => { - count += column.visible ? 1 : 0; - }); - return count; - } - - private getRowColor(item: any, index: number, row: DataTableRow) { - if (this.rowColors !== undefined) { - return (this.rowColors)(item, row, index); - } - } - - // selection: - - selectedRow: DataTableRow; - selectedRows: DataTableRow[] = []; - - private _selectAllCheckbox = false; - - get selectAllCheckbox() { - return this._selectAllCheckbox; - } - - set selectAllCheckbox(value) { - this._selectAllCheckbox = value; - this._onSelectAllChanged(value); - } - - private _onSelectAllChanged(value: boolean) { - this.rows.toArray().forEach(row => row.selected = value); - } - - onRowSelectChanged(row: DataTableRow) { - - // maintain the selectedRow(s) view - if (this.multiSelect) { - let index = this.selectedRows.indexOf(row); - if (row.selected && index < 0) { - this.selectedRows.push(row); - } else if (!row.selected && index >= 0) { - this.selectedRows.splice(index, 1); - } - } else { - if (row.selected) { - this.selectedRow = row; - } else if (this.selectedRow === row) { - this.selectedRow = undefined; - } - } - - // unselect all other rows: - if (row.selected && !this.multiSelect) { - this.rows.toArray().filter(row_ => row_.selected).forEach(row_ => { - if (row_ !== row) { // avoid endless loop - row_.selected = false; - } - }); - } - } - - // other: - - get substituteItems() { - return Array.from({ length: this.displayParams.limit - this.items.length }); - } - - // column resizing: - - private _resizeInProgress = false; - - private resizeColumnStart(event: MouseEvent, column: DataTableColumn, columnElement: HTMLElement) { - this._resizeInProgress = true; - - drag(event, { - move: (moveEvent: MouseEvent, dx: number) => { - if (this._isResizeInLimit(columnElement, dx)) { - column.width = columnElement.offsetWidth + dx; - } - }, - }); - } - - resizeLimit = 30; - - private _isResizeInLimit(columnElement: HTMLElement, dx: number) { - /* This is needed because CSS min-width didn't work on table-layout: fixed. - Without the limits, resizing can make the next column disappear completely, - and even increase the table width. The current implementation suffers from the fact, - that offsetWidth sometimes contains out-of-date values. */ - if ((dx < 0 && (columnElement.offsetWidth + dx) <= this.resizeLimit) || - !columnElement.nextElementSibling || // resizing doesn't make sense for the last visible column - (dx >= 0 && (( columnElement.nextElementSibling).offsetWidth + dx) <= this.resizeLimit)) { - return false; - } - return true; - } + private _items: any[] = []; + + @Input() get items() { + return this._items; + } + + set items(items: any[]) { + this._items = items; + this._onReloadFinished(); + } + + @Input() itemCount: number; + + // UI components: + + @ContentChildren(DataTableColumn) columns: QueryList; + @ViewChildren(DataTableRow) rows: QueryList; + @ContentChild('dataTableExpand') expandTemplate: TemplateRef; + + // One-time optional bindings with default values: + + @Input() headerTitle: string; + @Input() header = true; + @Input() pagination = true; + @Input() pagination_range = false; + @Input() pagination_limit = false; + @Input() pagination_input = false; + @Input() pagination_numbers = true; + @Input() indexColumn = true; + @Input() indexColumnHeader = ''; + @Input() rowColors: RowCallback; + @Input() rowTooltip: RowCallback; + @Input() selectColumn = false; + @Input() multiSelect = true; + @Input() substituteRows = true; + @Input() expandableRows = false; + @Input() translations: DataTableTranslations = defaultTranslations; + @Input() selectOnRowClick = false; + @Input() autoReload = true; + @Input() showReloading = false; + @Input() noDataMessage: string; + + // UI state without input: + + indexColumnVisible: boolean; + selectColumnVisible: boolean; + expandColumnVisible: boolean; + + // UI state: visible ge/set for the outside with @Input for one-time initial values + + private _sortBy: string; + private _sortAsc = true; + + private _offset = 0; + private _limit = 10; + + @Input() + get sortBy() { + return this._sortBy; + } + + set sortBy(value) { + this._sortBy = value; + this._triggerReload(); + } + + @Input() + get sortAsc() { + return this._sortAsc; + } + + set sortAsc(value) { + this._sortAsc = value; + this._triggerReload(); + } + + @Input() + get offset() { + return this._offset; + } + + set offset(value) { + this._offset = value; + this._triggerReload(); + } + + @Input() + get limit() { + return this._limit; + } + + set limit(value) { + this._limit = value; + this._triggerReload(); + } + + // calculated property: + + @Input() + get page() { + return Math.floor(this.offset / this.limit) + 1; + } + + set page(value) { + this.offset = (value - 1) * this.limit; + } + + get lastPage() { + return Math.ceil(this.itemCount / this.limit); + } + + // setting multiple observable properties simultaneously + + sort(sortBy: string, asc: boolean) { + this.sortBy = sortBy; + this.sortAsc = asc; + } + + // init + + ngOnInit() { + this._initDefaultValues(); + this._initDefaultClickEvents(); + this._updateDisplayParams(); + + if (this.autoReload && this._scheduledReload == null) { + this.reloadItems(); + } + } + + private _initDefaultValues() { + this.indexColumnVisible = this.indexColumn; + this.selectColumnVisible = this.selectColumn; + this.expandColumnVisible = this.expandableRows; + } + + private _initDefaultClickEvents() { + this.headerClick.subscribe(tableEvent => this.sortColumn(tableEvent.column)); + if (this.selectOnRowClick) { + this.rowClick.subscribe(tableEvent => tableEvent.row.selected = !tableEvent.row.selected); + } + } + + // Reloading: + + _reloading = false; + + get reloading() { + return this._reloading; + } + + @Output() reload = new EventEmitter(); + + reloadItems() { + this._reloading = true; + this.reload.emit(this._getRemoteParameters()); + } + + private _onReloadFinished() { + this._updateDisplayParams(); + + this._selectAllCheckbox = false; + this._reloading = false; + } + + _displayParams = {}; // params of the last finished reload + + get displayParams() { + return this._displayParams; + } + + _updateDisplayParams() { + this._displayParams = { + sortBy: this.sortBy, + sortAsc: this.sortAsc, + offset: this.offset, + limit: this.limit + }; + } + + _scheduledReload = null; + + // for avoiding cascading reloads if multiple params are set at once: + _triggerReload() { + if (this._scheduledReload) { + clearTimeout(this._scheduledReload); + } + this._scheduledReload = setTimeout(() => { + this.reloadItems(); + }); + } + + // event handlers: + + @Output() rowClick = new EventEmitter(); + @Output() rowDoubleClick = new EventEmitter(); + @Output() headerClick = new EventEmitter(); + @Output() cellClick = new EventEmitter(); + + public rowClicked(row: DataTableRow, event) { + this.rowClick.emit({ row, event }); + } + + public rowDoubleClicked(row: DataTableRow, event) { + this.rowDoubleClick.emit({ row, event }); + } + + private headerClicked(column: DataTableColumn, event: Event) { + if (!this._resizeInProgress) { + event.preventDefault(); + event.stopPropagation(); + this.headerClick.emit({ column, event }); + } else { + this._resizeInProgress = false; // this is because I can't prevent click from mousup of the drag end + } + } + + private cellClicked(column: DataTableColumn, row: DataTableRow, event: MouseEvent) { + this.cellClick.emit({ row, column, event }); + } + + // functions: + + private _getRemoteParameters(): DataTableParams { + let params = {}; + + if (this.sortBy) { + params.sortBy = this.sortBy; + params.sortAsc = this.sortAsc; + } + if (this.pagination) { + params.offset = this.offset; + params.limit = this.limit; + } + return params; + } + + private sortColumn(column: DataTableColumn) { + if (column.sortable) { + let ascending = this.sortBy === column.property ? !this.sortAsc : true; + this.sort(column.property, ascending); + } + } + + get columnCount() { + let count = 0; + count += this.indexColumnVisible ? 1 : 0; + count += this.selectColumnVisible ? 1 : 0; + count += this.expandColumnVisible ? 1 : 0; + this.columns.toArray().forEach(column => { + count += column.visible ? 1 : 0; + }); + return count; + } + + public getRowColor(item: any, index: number, row: DataTableRow) { + if (this.rowColors !== undefined) { + return (this.rowColors)(item, row, index); + } + } + + // selection: + + selectedRow: DataTableRow; + selectedRows: DataTableRow[] = []; + + private _selectAllCheckbox = false; + + get selectAllCheckbox() { + return this._selectAllCheckbox; + } + + set selectAllCheckbox(value) { + this._selectAllCheckbox = value; + this._onSelectAllChanged(value); + } + + private _onSelectAllChanged(value: boolean) { + this.rows.toArray().forEach(row => row.selected = value); + } + + onRowSelectChanged(row: DataTableRow) { + + // maintain the selectedRow(s) view + if (this.multiSelect) { + let index = this.selectedRows.indexOf(row); + if (row.selected && index < 0) { + this.selectedRows.push(row); + } else if (!row.selected && index >= 0) { + this.selectedRows.splice(index, 1); + } + } else { + if (row.selected) { + this.selectedRow = row; + } else if (this.selectedRow === row) { + this.selectedRow = undefined; + } + } + + // unselect all other rows: + if (row.selected && !this.multiSelect) { + this.rows.toArray().filter(row_ => row_.selected).forEach(row_ => { + if (row_ !== row) { // avoid endless loop + row_.selected = false; + } + }); + } + } + + // other: + + get substituteItems() { + return Array.from({ length: this.displayParams.limit - this.items.length }); + } + + // column resizing: + + private _resizeInProgress = false; + + private resizeColumnStart(event: MouseEvent, column: DataTableColumn, columnElement: HTMLElement) { + this._resizeInProgress = true; + + drag(event, { + move: (moveEvent: MouseEvent, dx: number) => { + if (this._isResizeInLimit(columnElement, dx)) { + column.width = columnElement.offsetWidth + dx; + } + }, + }); + } + + resizeLimit = 30; + + private _isResizeInLimit(columnElement: HTMLElement, dx: number) { + /* This is needed because CSS min-width didn't work on table-layout: fixed. + Without the limits, resizing can make the next column disappear completely, + and even increase the table width. The current implementation suffers from the fact, + that offsetWidth sometimes contains out-of-date values. */ + if ((dx < 0 && (columnElement.offsetWidth + dx) <= this.resizeLimit) || + !columnElement.nextElementSibling || // resizing doesn't make sense for the last visible column + (dx >= 0 && (( columnElement.nextElementSibling).offsetWidth + dx) <= this.resizeLimit)) { + return false; + } + return true; + } } diff --git a/src/components/table.template.ts b/src/components/table.template.ts index 14cdd8c..4974b08 100644 --- a/src/components/table.template.ts +++ b/src/components/table.template.ts @@ -6,23 +6,26 @@ export const TABLE_TEMPLATE = ` - - - + + + + + - + -`; \ No newline at end of file +`; diff --git a/src/components/types.ts b/src/components/types.ts deleted file mode 100644 index 30769ec..0000000 --- a/src/components/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { DataTableRow } from './row.component'; -import { DataTableColumn } from './column.component'; - - -export type RowCallback = (item: any, row: DataTableRow, index: number) => string; - -export type CellCallback = (item: any, row: DataTableRow, column: DataTableColumn, index: number) => string; - -// export type HeaderCallback = (column: DataTableColumn) => string; - - -export interface DataTableTranslations { - indexColumn: string; - selectColumn: string; - expandColumn: string; - paginationLimit: string; - paginationRange: string; -} - -export var defaultTranslations = { - indexColumn: 'index', - selectColumn: 'select', - expandColumn: 'expand', - paginationLimit: 'Limit', - paginationRange: 'Results' -}; - - -export interface DataTableParams { - offset?: number; - limit?: number; - sortBy?: string; - sortAsc?: boolean; -} diff --git a/src/index.ts b/src/index.ts index ac90400..2b4b8c0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,11 +11,14 @@ import { DataTableHeader } from './components/header.component'; import { PixelConverter } from './utils/px'; import { Hide } from './utils/hide'; import { MinPipe } from './utils/min'; - -export * from './components/types'; +import { DataTableTranslations } from './types/data-table-translations.type'; +import { CellCallback } from './types/cell-callback.type'; +import { RowCallback } from './types/row-callback.type'; +import { DataTableParams } from './types/data-table-params.type'; +import { defaultTranslations } from './types/default-translations.type'; export * from './tools/data-table-resource'; - -export { DataTable, DataTableColumn, DataTableRow, DataTablePagination, DataTableHeader }; +export { DataTable, DataTableColumn, DataTableRow, DataTablePagination, + DataTableHeader, DataTableTranslations, CellCallback, RowCallback, DataTableParams, defaultTranslations}; export const DATA_TABLE_DIRECTIVES = [ DataTable, DataTableColumn ]; @@ -28,4 +31,4 @@ export const DATA_TABLE_DIRECTIVES = [ DataTable, DataTableColumn ]; ], exports: [ DataTable, DataTableColumn ] }) -export class DataTableModule { } \ No newline at end of file +export class DataTableModule { } diff --git a/src/tools/data-table-resource.ts b/src/tools/data-table-resource.ts index 31a2768..5c74e39 100644 --- a/src/tools/data-table-resource.ts +++ b/src/tools/data-table-resource.ts @@ -1,4 +1,4 @@ -import { DataTableParams } from '../components/types'; +import { DataTableParams } from '../types/data-table-params.type'; export class DataTableResource { diff --git a/src/types/cell-callback.type.ts b/src/types/cell-callback.type.ts new file mode 100644 index 0000000..8636d01 --- /dev/null +++ b/src/types/cell-callback.type.ts @@ -0,0 +1,4 @@ +import { DataTableRow } from '../components/row.component'; +import { DataTableColumn } from '../components/column.component'; + +export type CellCallback = (item: any, row: DataTableRow, column: DataTableColumn, index: number) => string; diff --git a/src/types/data-table-params.type.ts b/src/types/data-table-params.type.ts new file mode 100644 index 0000000..1aac0d0 --- /dev/null +++ b/src/types/data-table-params.type.ts @@ -0,0 +1,6 @@ +export interface DataTableParams { + offset?: number; + limit?: number; + sortBy?: string; + sortAsc?: boolean; +} diff --git a/src/types/data-table-translations.type.ts b/src/types/data-table-translations.type.ts new file mode 100644 index 0000000..77f609e --- /dev/null +++ b/src/types/data-table-translations.type.ts @@ -0,0 +1,12 @@ +export interface DataTableTranslations { + headerReload: string, + headerColumnSelector: string, + indexColumn: string; + selectColumn: string; + selectRow: string; + selectAllRows: string, + expandColumn: string; + expandRow: string; + paginationLimit: string; + paginationRange: string; +} diff --git a/src/types/default-translations.type.ts b/src/types/default-translations.type.ts new file mode 100644 index 0000000..bdd3123 --- /dev/null +++ b/src/types/default-translations.type.ts @@ -0,0 +1,14 @@ +import {DataTableTranslations} from'./data-table-translations.type' + +export const defaultTranslations: DataTableTranslations = { + headerReload: 'reload', + headerColumnSelector: 'column selector', + indexColumn: 'index', + selectColumn: 'select', + selectRow: 'select', + selectAllRows: 'select', + expandColumn: 'expand', + expandRow: 'expand', + paginationLimit: 'Limit', + paginationRange: 'Results' +}; diff --git a/src/types/row-callback.type.ts b/src/types/row-callback.type.ts new file mode 100644 index 0000000..d80637d --- /dev/null +++ b/src/types/row-callback.type.ts @@ -0,0 +1,3 @@ +import { DataTableRow } from '../components/row.component'; + +export type RowCallback = (item: any, row: DataTableRow, index: number) => string; diff --git a/tsconfig.json b/tsconfig.json index afa16d1..8962384 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,5 @@ { - "compileOnSave": false, + "compileOnSave": true, "compilerOptions": { "declaration": true, "emitDecoratorMetadata": true, @@ -9,15 +9,26 @@ "moduleResolution": "node", "noEmitOnError": true, "noImplicitAny": false, + "preserveConstEnums": true, "outDir": "dist/", "rootDir": "src/", + "types" : ["node"], "sourceMap": true, "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2016", + "dom" + ], "inlineSources": true }, "exclude": [ - "dist", "node_modules", "index.ts" - ] + ], + "angularCompilerOptions": { + "skipTemplateCodegen": true + } } diff --git a/typings.json b/typings.json deleted file mode 100644 index b0bb089..0000000 --- a/typings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "angular-2-data-table", - "dependencies": {}, - "globalDevDependencies": { - "es6-shim": "registry:dt/es6-shim#0.31.2+20160602141504" - } -}
- + + - + + + [ngClass]="column.styleClassObject" class="column-header" [style.width]="column.width | px" + [attr.aria-sort]="column.sortable ? (column.property === sortBy ? (sortAsc ? 'ascending' : 'descending') : 'none') : null" + [attr.tabindex]="column.sortable ? '0' : null"> - - + @@ -32,6 +35,11 @@ export const TABLE_TEMPLATE = `
{{ noDataMessage }}