angular2-data-table
Version:
angular2-data-table is a Angular2 component for presenting large and complex data.
446 lines • 18.1 kB
JavaScript
"use strict";
var core_1 = require('@angular/core');
var utils_1 = require('../../utils');
var scroller_component_1 = require('./scroller.component');
var DataTableBodyComponent = (function () {
function DataTableBodyComponent() {
this.selected = [];
this.scroll = new core_1.EventEmitter();
this.page = new core_1.EventEmitter();
this.activate = new core_1.EventEmitter();
this.select = new core_1.EventEmitter();
this.detailToggle = new core_1.EventEmitter();
this.rowContextmenu = new core_1.EventEmitter(false);
this.rowHeightsCache = new utils_1.RowHeightCache();
this.temp = [];
this.offsetY = 0;
this.indexes = {};
// declare fn here so we can get access to the `this` property
this.rowTrackingFn = function (index, row) {
if (this.trackByProp) {
return row.$$index + "-" + this.trackByProp;
}
else {
return row.$$index;
}
}.bind(this);
}
Object.defineProperty(DataTableBodyComponent.prototype, "pageSize", {
get: function () {
return this._pageSize;
},
set: function (val) {
this._pageSize = val;
this.recalcLayout();
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "rows", {
get: function () {
return this._rows;
},
set: function (val) {
this._rows = val;
this.recalcLayout();
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "columns", {
get: function () {
return this._columns;
},
set: function (val) {
this._columns = val;
var colsByPin = utils_1.columnsByPin(val);
this.columnGroupWidths = utils_1.columnGroupWidths(colsByPin, val);
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "offset", {
get: function () {
return this._offset;
},
set: function (val) {
this._offset = val;
this.recalcLayout();
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "rowCount", {
get: function () {
return this._rowCount;
},
set: function (val) {
this._rowCount = val;
this.recalcLayout();
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "bodyWidth", {
get: function () {
if (this.scrollbarH) {
return this.innerWidth + 'px';
}
else {
return '100%';
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "bodyHeight", {
get: function () {
return this._bodyHeight;
},
set: function (val) {
if (this.scrollbarV) {
this._bodyHeight = val + 'px';
}
else {
this._bodyHeight = 'auto';
}
this.recalcLayout();
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "selectEnabled", {
/**
* Returns if selection is enabled.
*
* @readonly
* @type {boolean}
* @memberOf DataTableBodyComponent
*/
get: function () {
return !!this.selectionType;
},
enumerable: true,
configurable: true
});
Object.defineProperty(DataTableBodyComponent.prototype, "scrollHeight", {
/**
* Property that would calculate the height of scroll bar
* based on the row heights cache for virtual scroll. Other scenarios
* calculate scroll height automatically (as height will be undefined).
*
* @readonly
* @type {number}
* @memberOf DataTableBodyComponent
*/
get: function () {
if (this.scrollbarV) {
return this.rowHeightsCache.query(this.rowCount - 1);
}
},
enumerable: true,
configurable: true
});
/**
* Updates the Y offset given a new offset.
*
* @param {number} [offset]
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.updateOffsetY = function (offset) {
if (this.scrollbarV && offset) {
// First get the row Index that we need to move to.
var rowIndex = this.pageSize * offset;
offset = this.rowHeightsCache.query(rowIndex - 1);
}
this.scroller.setOffset(offset || 0);
};
/**
* Body was scrolled, this is mainly useful for
* when a user is server-side pagination via virtual scroll.
*
* @param {*} event
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.onBodyScroll = function (event) {
var scrollYPos = event.scrollYPos;
var scrollXPos = event.scrollXPos;
// if scroll change, trigger update
// this is mainly used for header cell positions
if (this.offsetY !== scrollYPos || this.offsetX !== scrollXPos) {
this.scroll.emit({
offsetY: scrollYPos,
offsetX: scrollXPos
});
}
this.offsetY = scrollYPos;
this.offsetX = scrollXPos;
this.updateIndexes();
this.updatePage(event.direction);
this.updateRows();
};
/**
* Updates the page given a direction.
*
* @param {string} direction
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.updatePage = function (direction) {
var offset = this.indexes.first / this.pageSize;
if (direction === 'up') {
offset = Math.floor(offset);
}
else if (direction === 'down') {
offset = Math.ceil(offset);
}
if (direction !== undefined && !isNaN(offset)) {
this.page.emit({ offset: offset });
}
};
/**
* Updates the rows in the view port
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.updateRows = function () {
var _a = this.indexes, first = _a.first, last = _a.last;
var rowIndex = first;
var idx = 0;
var temp = [];
while (rowIndex < last && rowIndex < this.rowCount) {
var row = this.rows[rowIndex];
if (row) {
row.$$index = rowIndex;
temp[idx] = row;
}
idx++;
rowIndex++;
}
this.temp = temp;
};
/**
* Calculate row height based on the expanded state of the row.
*
* @param {*} row the row for which the height need to be calculated.
* @returns {number} height of the row.
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.getRowHeight = function (row) {
// Adding detail row height if its expanded.
return this.rowHeight +
(row.$$expanded === 1 ? this.detailRowHeight : 0);
};
/**
* Calculates the styles for the row so that the rows can be moved in 2D space
* during virtual scroll inside the DOM. In the below case the Y position is
* manipulated. As an example, if the height of row 0 is 30 px and row 1 is
* 100 px then following styles are generated:
*
* transform: translate3d(0px, 0px, 0px); -> row0
* transform: translate3d(0px, 30px, 0px); -> row1
* transform: translate3d(0px, 130px, 0px); -> row2
*
* Row heights have to be calculated based on the row heights cache as we wont
* be able to determine which row is of what height before hand. In the above
* case the positionY of the translate3d for row2 would be the sum of all the
* heights of the rows before it (i.e. row0 and row1).
*
* @param {*} row The row that needs to be placed in the 2D space.
* @returns {*} Returns the CSS3 style to be applied
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.getRowsStyles = function (row) {
var rowHeight = this.getRowHeight(row);
var styles = {
height: rowHeight + 'px'
};
if (this.scrollbarV) {
var idx = row ? row.$$index : 0;
// const pos = idx * rowHeight;
// The position of this row would be the sum of all row heights
// until the previous row position.
var pos = this.rowHeightsCache.query(idx - 1);
utils_1.translateXY(styles, 0, pos);
}
return styles;
};
/**
* Hides the loading indicator
*
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.hideIndicator = function () {
var _this = this;
setTimeout(function () { return _this.loadingIndicator = false; }, 500);
};
/**
* Updates the index of the rows in the viewport
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.updateIndexes = function () {
var first = 0;
var last = 0;
if (this.scrollbarV) {
// Calculation of the first and last indexes will be based on where the
// scrollY position would be at. The last index would be the one
// that shows up inside the view port the last.
var height = parseInt(this.bodyHeight, 0);
first = this.rowHeightsCache.getRowIndex(this.offsetY);
last = this.rowHeightsCache.getRowIndex(height + this.offsetY) + 1;
}
else {
first = Math.max(this.offset * this.pageSize, 0);
last = Math.min((first + this.pageSize), this.rowCount);
}
this.indexes = { first: first, last: last };
};
/**
* Refreshes the full Row Height cache. Should be used
* when the entire row array state has changed.
*
* @returns {void}
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.refreshRowHeightCache = function () {
if (!this.scrollbarV)
return;
// clear the previous row height cache if already present.
// this is useful during sorts, filters where the state of the
// rows array is changed.
this.rowHeightsCache.clearCache();
// Initialize the tree only if there are rows inside the tree.
if (this.rows && this.rows.length) {
this.rowHeightsCache.initCache(this.rows, this.rowHeight, this.detailRowHeight);
}
};
/**
* Gets the index for the view port
*
* @returns {number}
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.getAdjustedViewPortIndex = function () {
// Capture the row index of the first row that is visible on the viewport.
// If the scroll bar is just below the row which is highlighted then make that as the
// first index.
var viewPortFirstRowIndex = this.indexes.first;
if (this.scrollbarV) {
var offsetScroll = this.rowHeightsCache.query(viewPortFirstRowIndex - 1);
return offsetScroll <= this.offsetY ? viewPortFirstRowIndex - 1 : viewPortFirstRowIndex;
}
return viewPortFirstRowIndex;
};
/**
* Toggle the Expansion of the row i.e. if the row is expanded then it will
* collapse and vice versa. Note that the expanded status is stored as
* a part of the row object itself as we have to preserve the expanded row
* status in case of sorting and filtering of the row set.
*
* @param {*} row The row for which the expansion needs to be toggled.
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.toggleRowExpansion = function (row) {
// Capture the row index of the first row that is visible on the viewport.
var viewPortFirstRowIndex = this.getAdjustedViewPortIndex();
// If the detailRowHeight is auto --> only in case of non-virtualized scroll
if (this.scrollbarV) {
var detailRowHeight = this.detailRowHeight * (row.$$expanded ? -1 : 1);
this.rowHeightsCache.update(row.$$index, detailRowHeight);
}
// Update the toggled row and update the heights in the cache.
row.$$expanded ^= 1;
this.detailToggle.emit({
rows: [row],
currentIndex: viewPortFirstRowIndex
});
};
/**
* Expand/Collapse all the rows no matter what their state is.
*
* @param {boolean} expanded When true, all rows are expanded and when false, all rows will be collapsed.
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.toggleAllRows = function (expanded) {
var rowExpanded = expanded ? 1 : 0;
// Capture the row index of the first row that is visible on the viewport.
var viewPortFirstRowIndex = this.getAdjustedViewPortIndex();
for (var _i = 0, _a = this.rows; _i < _a.length; _i++) {
var row = _a[_i];
row.$$expanded = rowExpanded;
}
if (this.scrollbarV) {
// Refresh the full row heights cache since every row was affected.
this.refreshRowHeightCache();
}
// Emit all rows that have been expanded.
this.detailToggle.emit({
rows: this.rows,
currentIndex: viewPortFirstRowIndex
});
};
/**
* Recalculates the table
*
* @memberOf DataTableBodyComponent
*/
DataTableBodyComponent.prototype.recalcLayout = function () {
this.refreshRowHeightCache();
this.updateIndexes();
this.updateRows();
};
DataTableBodyComponent.decorators = [
{ type: core_1.Component, args: [{
selector: 'datatable-body',
template: "\n <datatable-selection\n #selector\n [selected]=\"selected\"\n [rows]=\"temp\"\n [selectCheck]=\"selectCheck\"\n [selectEnabled]=\"selectEnabled\"\n [selectionType]=\"selectionType\"\n [rowIdentity]=\"rowIdentity\"\n (select)=\"select.emit($event)\"\n (activate)=\"activate.emit($event)\">\n <datatable-progress\n *ngIf=\"loadingIndicator\">\n </datatable-progress>\n <datatable-scroller\n *ngIf=\"rows?.length\"\n [scrollbarV]=\"scrollbarV\"\n [scrollbarH]=\"scrollbarH\"\n [scrollHeight]=\"scrollHeight\"\n [scrollWidth]=\"columnGroupWidths.total\"\n (scroll)=\"onBodyScroll($event)\">\n <datatable-row-wrapper\n *ngFor=\"let row of temp; let i = index; trackBy: rowTrackingFn;\"\n [ngStyle]=\"getRowsStyles(row)\"\n [rowDetailTemplate]=\"rowDetailTemplate\"\n [detailRowHeight]=\"detailRowHeight\"\n [row]=\"row\"\n [expanded]=\"row.$$expanded === 1\"\n (rowContextmenu)=\"rowContextmenu.emit($event)\">\n <datatable-body-row\n tabindex=\"-1\"\n [isSelected]=\"selector.getRowSelected(row)\"\n [innerWidth]=\"innerWidth\"\n [offsetX]=\"offsetX\"\n [columns]=\"columns\"\n [rowHeight]=\"rowHeight\"\n [row]=\"row\"\n (activate)=\"selector.onActivate($event, i)\">\n </datatable-body-row>\n </datatable-row-wrapper>\n </datatable-scroller>\n <div\n class=\"empty-row\"\n *ngIf=\"!rows?.length\"\n [innerHTML]=\"emptyMessage\">\n </div>\n </datatable-selection>\n ",
host: {
class: 'datatable-body'
}
},] },
];
/** @nocollapse */
DataTableBodyComponent.ctorParameters = function () { return []; };
DataTableBodyComponent.propDecorators = {
'scrollbarV': [{ type: core_1.Input },],
'scrollbarH': [{ type: core_1.Input },],
'loadingIndicator': [{ type: core_1.Input },],
'rowHeight': [{ type: core_1.Input },],
'offsetX': [{ type: core_1.Input },],
'detailRowHeight': [{ type: core_1.Input },],
'emptyMessage': [{ type: core_1.Input },],
'selectionType': [{ type: core_1.Input },],
'selected': [{ type: core_1.Input },],
'rowIdentity': [{ type: core_1.Input },],
'rowDetailTemplate': [{ type: core_1.Input },],
'selectCheck': [{ type: core_1.Input },],
'trackByProp': [{ type: core_1.Input },],
'pageSize': [{ type: core_1.Input },],
'rows': [{ type: core_1.Input },],
'columns': [{ type: core_1.Input },],
'offset': [{ type: core_1.Input },],
'rowCount': [{ type: core_1.Input },],
'innerWidth': [{ type: core_1.Input },],
'bodyWidth': [{ type: core_1.HostBinding, args: ['style.width',] },],
'bodyHeight': [{ type: core_1.Input }, { type: core_1.HostBinding, args: ['style.height',] },],
'scroll': [{ type: core_1.Output },],
'page': [{ type: core_1.Output },],
'activate': [{ type: core_1.Output },],
'select': [{ type: core_1.Output },],
'detailToggle': [{ type: core_1.Output },],
'rowContextmenu': [{ type: core_1.Output },],
'scroller': [{ type: core_1.ViewChild, args: [scroller_component_1.ScrollerComponent,] },],
};
return DataTableBodyComponent;
}());
exports.DataTableBodyComponent = DataTableBodyComponent;
//# sourceMappingURL=body.component.js.map