@bi8/am-data-table
Version:
ng update @angular/cli --migrate-only --from=1.7.4 ng update @angular/core yarn add ng-packagr yarn add @angular/material yarn add core-js yarn add @angular/flex-layout yarn add lodash yarn add material-design-icons yarn add roboto-fontface yarn
1,095 lines (1,083 loc) • 132 kB
JavaScript
import * as tslib_1 from "tslib";
import { AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, Directive, ElementRef, EventEmitter, forwardRef, Inject, Injectable, InjectionToken, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, OnChanges, OnDestroy, OnInit, Optional, Output, QueryList, Renderer2, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { DataSource } from '@angular/cdk/collections';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import * as _ from 'lodash';
import { takeUntil } from 'rxjs/operator/takeUntil';
export const AM_GRID_DATE_FORMAT = new InjectionToken('am.grid.date.format');
export const AM_GRID_DATE_DEFAULT = {
format: 'fullDate'
};
//=====[ UTILS ]======================================================================================================================================
function toCssFriendly(value) {
// the string value is typically generated from the column key that may contain '.'
return value ? value.split('.').map(item => _.kebabCase(item)).join('-') : value;
}
//=====[ OUTLETS ]====================================================================================================================================
let HeaderRowOutlet = class HeaderRowOutlet {
constructor(viewContainer) {
this.viewContainer = viewContainer;
}
};
HeaderRowOutlet.ctorParameters = () => [
{ type: ViewContainerRef }
];
HeaderRowOutlet = tslib_1.__decorate([
Directive({ selector: '[headerRowOutlet]' }),
tslib_1.__metadata("design:paramtypes", [ViewContainerRef])
], HeaderRowOutlet);
export { HeaderRowOutlet };
let DataRowOutlet = class DataRowOutlet {
constructor(viewContainer) {
this.viewContainer = viewContainer;
}
};
DataRowOutlet.ctorParameters = () => [
{ type: ViewContainerRef }
];
DataRowOutlet = tslib_1.__decorate([
Directive({ selector: '[dataRowOutlet]' }),
tslib_1.__metadata("design:paramtypes", [ViewContainerRef])
], DataRowOutlet);
export { DataRowOutlet };
let RowOutlet = class RowOutlet {
constructor(viewContainer) {
this.viewContainer = viewContainer;
}
};
RowOutlet.ctorParameters = () => [
{ type: ViewContainerRef }
];
RowOutlet = tslib_1.__decorate([
Directive({ selector: '[rowOutlet]' }),
tslib_1.__metadata("design:paramtypes", [ViewContainerRef])
], RowOutlet);
export { RowOutlet };
let ExpanderOutlet = class ExpanderOutlet {
constructor(viewContainer) {
this.viewContainer = viewContainer;
}
};
ExpanderOutlet.ctorParameters = () => [
{ type: ViewContainerRef }
];
ExpanderOutlet = tslib_1.__decorate([
Directive({ selector: '[expanderOutlet]' }),
tslib_1.__metadata("design:paramtypes", [ViewContainerRef])
], ExpanderOutlet);
export { ExpanderOutlet };
let CellOutlet = class CellOutlet {
constructor(viewContainer) {
this.viewContainer = viewContainer;
}
};
CellOutlet.ctorParameters = () => [
{ type: ViewContainerRef }
];
CellOutlet = tslib_1.__decorate([
Directive({ selector: '[cellOutlet]' }),
tslib_1.__metadata("design:paramtypes", [ViewContainerRef])
], CellOutlet);
export { CellOutlet };
//=====[ HEADER ROW ]=================================================================================================================================
let HeaderRowDef = class HeaderRowDef {
constructor(templateRef, viewContainer) {
this.templateRef = templateRef;
this.viewContainer = viewContainer;
}
};
HeaderRowDef.ctorParameters = () => [
{ type: TemplateRef },
{ type: ViewContainerRef }
];
HeaderRowDef = tslib_1.__decorate([
Directive({
selector: '[headerRowDef]',
inputs: ['model: headerRowDef']
}),
tslib_1.__metadata("design:paramtypes", [TemplateRef, ViewContainerRef])
], HeaderRowDef);
export { HeaderRowDef };
let HeaderCellDef = class HeaderCellDef {
constructor(templateRef, viewContainer) {
this.templateRef = templateRef;
this.viewContainer = viewContainer;
}
};
HeaderCellDef.ctorParameters = () => [
{ type: TemplateRef },
{ type: ViewContainerRef }
];
HeaderCellDef = tslib_1.__decorate([
Directive({
selector: '[headerCellDef]',
inputs: ['column: column']
}),
tslib_1.__metadata("design:paramtypes", [TemplateRef,
ViewContainerRef])
], HeaderCellDef);
export { HeaderCellDef };
let HeaderCell = class HeaderCell {
constructor(componentFactoryResolver, elementRef, renderer) {
this.componentFactoryResolver = componentFactoryResolver;
this.elementRef = elementRef;
this.renderer = renderer;
}
ngOnInit() {
this.renderer.addClass(this.elementRef.nativeElement, `am-header-cell-${toCssFriendly(this.column.config.key)}`);
this.renderer.setStyle(this.elementRef.nativeElement, 'flex', this.column.styles.flex || 1);
if (this.column && this.column.styles.minWidth) {
this.renderer.setStyle(this.elementRef.nativeElement, 'min-width', this.column.styles.minWidth);
}
else if (this.column && this.column.model) {
if (this.column.model.styles.minColumnWidth) {
this.renderer.setStyle(this.elementRef.nativeElement, 'min-width', this.column.model.styles.minColumnWidth);
}
}
if (this.column.styles.headerCellStyleClasses) {
this.column.styles.headerCellStyleClasses.forEach((cls, index) => {
this.renderer.addClass(this.elementRef.nativeElement, cls);
});
}
}
ngOnChanges(changes) {
}
ngOnDestroy() {
}
ngAfterContentInit() {
this.renderCell();
}
renderCell() {
this._cellOutlet.viewContainer.clear();
if (this.column.config.headingTemplate) {
this._cellOutlet.viewContainer.createEmbeddedView(this.column.config.headingTemplate, { column: this.column });
}
else {
let formatter = this.column.config.headingFormatter;
if (formatter) {
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(formatter);
let viewContainerRef = this._cellOutlet.viewContainer;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent(componentFactory);
componentRef.instance.column = this.column;
}
else {
console.warn(`Could not find header formatter for column with key '${this.column.config.key}'.`);
}
}
}
};
HeaderCell.ctorParameters = () => [
{ type: ComponentFactoryResolver },
{ type: ElementRef },
{ type: Renderer2 }
];
tslib_1.__decorate([
ViewChild(CellOutlet, { static: true }),
tslib_1.__metadata("design:type", CellOutlet)
], HeaderCell.prototype, "_cellOutlet", void 0);
HeaderCell = tslib_1.__decorate([
Component({
selector: 'header-cell',
inputs: ['column: column'],
template: `
<ng-container cellOutlet></ng-container>
`,
host: {
'class': 'am-header-cell',
'role': 'row',
},
encapsulation: ViewEncapsulation.None
}),
tslib_1.__metadata("design:paramtypes", [ComponentFactoryResolver,
ElementRef,
Renderer2])
], HeaderCell);
export { HeaderCell };
let HeaderRow = class HeaderRow {
constructor(_changeDetectorRef) {
this._changeDetectorRef = _changeDetectorRef;
this.events$ = new EventEmitter();
}
ngAfterContentInit() {
// first we clear the row container
this._rowOutlet.viewContainer.clear();
// then render each column
this.model.columns.forEach((column, index) => {
this.renderHeaderCell(column);
});
}
renderHeaderCell(column, index) {
this._rowOutlet.viewContainer.createEmbeddedView(this._headerCellDef.templateRef, { $implicit: column }, index);
}
clearCells() {
this._rowOutlet.viewContainer.clear();
}
/**
* Iterate the changes and apply add/remove/insert operations to the collection of header cells (columns)
* @todo - can still do the TODO one for moving a column (look at material2 data table sort for an example
*
*/
applyColumnChanges(changes) {
if (!changes) {
return;
}
// remove
changes.forEachRemovedItem((record) => {
//console.log("removing existing cell", record);
this._rowOutlet.viewContainer.remove(record.previousIndex);
this.events$.emit({
type: GridEventType.ColumnRemoved,
data: record
});
});
// add, insert
changes.forEachAddedItem((record) => {
//console.log("adding/inserting new cell for new column", record);
this.renderHeaderCell(record.item, record.currentIndex);
this.events$.emit({
type: GridEventType.ColumnAdded,
data: record
});
});
// then tell Angular to do it's checks
this._changeDetectorRef.markForCheck();
}
};
HeaderRow.ctorParameters = () => [
{ type: ChangeDetectorRef }
];
tslib_1.__decorate([
Output('events'),
tslib_1.__metadata("design:type", Object)
], HeaderRow.prototype, "events$", void 0);
tslib_1.__decorate([
ViewChild(RowOutlet, { static: true }),
tslib_1.__metadata("design:type", RowOutlet)
], HeaderRow.prototype, "_rowOutlet", void 0);
tslib_1.__decorate([
ViewChild(HeaderCellDef, { static: true }),
tslib_1.__metadata("design:type", HeaderCellDef)
], HeaderRow.prototype, "_headerCellDef", void 0);
tslib_1.__decorate([
ViewChildren(HeaderCell),
tslib_1.__metadata("design:type", QueryList)
], HeaderRow.prototype, "headerCells", void 0);
HeaderRow = tslib_1.__decorate([
Component({
selector: 'header-row',
inputs: ['model: model'],
template: `
<div *ngIf="model.config.showExpander" class="am-header-expander-column"></div>
<ng-container rowOutlet></ng-container>
<ng-container>
<header-cell *headerCellDef="let column;" [column]="column"></header-cell>
<!--<header-cell *headerCellDef="let column as column;" [column]="column"></header-cell>-->
</ng-container>
`,
host: {
'class': 'am-header-row',
'role': 'row',
},
encapsulation: ViewEncapsulation.None
}),
tslib_1.__metadata("design:paramtypes", [ChangeDetectorRef])
], HeaderRow);
export { HeaderRow };
let DataRowDef = class DataRowDef {
constructor(templateRef, viewContainer) {
this.templateRef = templateRef;
this.viewContainer = viewContainer;
}
};
DataRowDef.ctorParameters = () => [
{ type: TemplateRef },
{ type: ViewContainerRef }
];
DataRowDef = tslib_1.__decorate([
Directive({ selector: '[dataRowDef]', }),
tslib_1.__metadata("design:paramtypes", [TemplateRef,
ViewContainerRef])
], DataRowDef);
export { DataRowDef };
let DataCellDef = class DataCellDef {
constructor(templateRef, viewContainer) {
this.templateRef = templateRef;
this.viewContainer = viewContainer;
}
};
DataCellDef.ctorParameters = () => [
{ type: TemplateRef },
{ type: ViewContainerRef }
];
DataCellDef = tslib_1.__decorate([
Directive({ selector: '[dataCellDef]', }),
tslib_1.__metadata("design:paramtypes", [TemplateRef,
ViewContainerRef])
], DataCellDef);
export { DataCellDef };
let DataCell = class DataCell {
constructor(componentFactoryResolver, elementRef, renderer) {
this.componentFactoryResolver = componentFactoryResolver;
this.elementRef = elementRef;
this.renderer = renderer;
}
ngOnInit() {
this.renderer.addClass(this.elementRef.nativeElement, `am-data-cell-${toCssFriendly(this.column.config.key)}`);
this.renderer.setStyle(this.elementRef.nativeElement, 'flex', this.column.styles.flex || 1);
if (this.column && this.column.styles.minWidth) {
this.renderer.setStyle(this.elementRef.nativeElement, 'min-width', this.column.styles.minWidth);
}
else if (this.column && this.column.model) {
if (this.column.model.styles.minColumnWidth) {
this.renderer.setStyle(this.elementRef.nativeElement, 'min-width', this.column.model.styles.minColumnWidth);
}
}
if (this.column.styles.dataCellStyleClasses) {
this.column.styles.dataCellStyleClasses.forEach((cls, index) => {
this.renderer.addClass(this.elementRef.nativeElement, cls);
});
}
}
ngAfterContentInit() {
this.renderCell();
}
renderCell() {
/////////////console.log('DataCell: row:', this.row);
/////////////console.log('DataCell: column:', this.column);
//console.log(`rendering: ${this.column.config.key}`);
this._cellOutlet.viewContainer.clear();
if (this.column.config.dataTemplate) {
this._cellOutlet.viewContainer.createEmbeddedView(this.column.config.dataTemplate, { column: this.column, row: this.row });
}
else {
let formatter = this.column.config.formatter;
if (formatter) {
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(formatter);
let viewContainerRef = this._cellOutlet.viewContainer;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent(componentFactory);
componentRef.instance.column = this.column;
componentRef.instance.row = this.row;
}
else {
console.warn(`Could not find data formatter for column with key '${this.column.config.key}'.`);
}
}
}
};
DataCell.ctorParameters = () => [
{ type: ComponentFactoryResolver },
{ type: ElementRef },
{ type: Renderer2 }
];
tslib_1.__decorate([
ViewChild(CellOutlet, { static: true }),
tslib_1.__metadata("design:type", CellOutlet)
], DataCell.prototype, "_cellOutlet", void 0);
DataCell = tslib_1.__decorate([
Component({
selector: 'data-cell',
inputs: ['column: column', 'row: row'],
template: `
<ng-container cellOutlet></ng-container>
`,
host: {
'class': 'am-data-cell',
'role': 'row',
},
encapsulation: ViewEncapsulation.None
}),
tslib_1.__metadata("design:paramtypes", [ComponentFactoryResolver,
ElementRef,
Renderer2])
], DataCell);
export { DataCell };
const EXPANDER_ICON_CLOSED = 'keyboard_arrow_right';
const EXPANDER_ICON_OPEN = 'keyboard_arrow_down';
let DataRow = class DataRow {
constructor(_changeDetectorRef) {
this._changeDetectorRef = _changeDetectorRef;
this.events$ = new EventEmitter();
this.selected = false;
this.expanderIcon = EXPANDER_ICON_CLOSED;
}
rowClicked(event) {
this.events$.emit({
type: GridEventType.RowClicked,
data: this
});
}
selectRow() {
this.row.selected = true;
}
deselectRow() {
this.row.selected = false;
}
isSelected() {
return this.row.selected;
}
rowClass() {
if (this.row.model.styles.dataRowStyleResolver) {
return this.row.model.styles.dataRowStyleResolver(this.row);
}
else {
return this.row.selected ? ['default-selected-row'] : null;
}
}
cellClass(column) {
if (column.styles.dataCellStyleResolver) {
return column.styles.dataCellStyleResolver(this.row, column);
}
else {
return null;
}
}
ngAfterContentInit() {
/////////////console.log("DataRow: model:", this.row.model);
/////////////console.log("DataRow: row:", this.row.data);
// first we clear the row container
this._rowOutlet.viewContainer.clear();
// then render each column
this.row.model.columns.forEach((column, index) => {
this.renderDataCell(column);
});
}
renderDataCell(column, index) {
this._rowOutlet.viewContainer.createEmbeddedView(this._dataCellDef.templateRef, { $implicit: column, row: this.row }, index);
}
/**
* Iterate the changes and apply add/remove/insert operations to the collection of header cells (columns)
* @todo - can still do the TODO one for moving a column (look at material2 data table sort for an example
*
*/
applyColumnChanges(changes) {
if (!changes) {
return;
}
// add, insert
changes.forEachAddedItem((record) => {
/////////////console.log("adding/inserting new cell for new column", record);
this.renderDataCell(record.item, record.currentIndex);
});
// remove
changes.forEachRemovedItem((record) => {
/////////////console.log("removing existing cell", record);
this._rowOutlet.viewContainer.remove(record.previousIndex);
});
// then tell Angular to do it's checks
this._changeDetectorRef.markForCheck();
}
toggleExpander() {
this._expanderOutlet.viewContainer.clear();
if (this.row.expanded) {
this.row.expanded = false;
this.expanderIcon = EXPANDER_ICON_CLOSED;
}
else {
this.row.expanded = true;
this.expanderIcon = EXPANDER_ICON_OPEN;
if (this.row.model.config.expanderTemplate) {
this._expanderOutlet.viewContainer.createEmbeddedView(this.row.model.config.expanderTemplate, { row: this.row });
}
}
this.events$.emit({
type: this.row.expanded ? GridEventType.RowExpanded : GridEventType.RowContracted,
data: this.row
});
}
};
DataRow.ctorParameters = () => [
{ type: ChangeDetectorRef }
];
tslib_1.__decorate([
Output('events'),
tslib_1.__metadata("design:type", Object)
], DataRow.prototype, "events$", void 0);
tslib_1.__decorate([
ViewChild(RowOutlet, { static: true }),
tslib_1.__metadata("design:type", RowOutlet)
], DataRow.prototype, "_rowOutlet", void 0);
tslib_1.__decorate([
ViewChild(DataCellDef, { static: true }),
tslib_1.__metadata("design:type", DataCellDef)
], DataRow.prototype, "_dataCellDef", void 0);
tslib_1.__decorate([
ViewChildren(DataCell),
tslib_1.__metadata("design:type", QueryList)
], DataRow.prototype, "dataCells", void 0);
tslib_1.__decorate([
ViewChild(ExpanderOutlet, { static: true }),
tslib_1.__metadata("design:type", ExpanderOutlet)
], DataRow.prototype, "_expanderOutlet", void 0);
DataRow = tslib_1.__decorate([
Component({
selector: 'data-row',
inputs: ['row: row'],
template: `
<!--
Expander Status - show/hide/disable (also with a tooltip)
Expander Type - Chevron (expand/contract), Slider (slide-in/slide-out)
rowDataFormatter {
span: [
['firstName','lastName']
]
colSpan: ['firstName','lastName']
}
GridColumn
StackedGridColumn
emit({
type: RowExpanded / RowContracted,
data: record
})
emit({
type: RowAdded, RowRemoved
data: record
})
I would also like the ability
[ wildcard search ] - across all columns
---------------------------------------------------------------------
| | First Name | Mobile | Birth Date |
| | Surname | Email | Age |
---------------------------------------------------------------------
=====================================================================
[F]: | [ First Name ] | [ Mobile ] | [DATE-FORM] [DATE-TO] |
[ Last Name ] | [ Email ] | |
=====================================================================
| Manie | Coetzee | 77/05/05 |
> | Coetzee | mc@bla.com | 40 |
---------------------------------------------------------------------
| | 13 Pioneer Road |
| [ADDRESS] | Durbanville |
| | 7550 |
---------------------------------------------------------------------
EXPANDER
=====================================================================
\ \
\ \
\ \
\ \
=====================================================================
-->
<div style="flex: 1 1 auto; cursor: pointer;" [ngClass]="rowClass()" (click)="rowClicked($event)">
<div style="display: flex; flex: 1 1 auto;" [ngClass]="{'am-expanded-row': row.expanded && !rowClass()}">
<div *ngIf="row.model.config.showExpander" class="am-header-expander-column">
<mat-icon (click)="toggleExpander()">{{expanderIcon}}</mat-icon>
</div>
<ng-container rowOutlet></ng-container>
</div>
<div style="flex: 1 1 auto;" [ngClass]="{'am-expander-row': row.expanded}">
<ng-container expanderOutlet></ng-container>
</div>
</div>
<ng-container>
<data-cell *dataCellDef="let column; " [column]="column" [row]="row" [ngClass]="cellClass(column)"></data-cell>
</ng-container>
`,
host: {
'class': 'am-data-row',
'role': 'row',
},
encapsulation: ViewEncapsulation.None
}),
tslib_1.__metadata("design:paramtypes", [ChangeDetectorRef])
], DataRow);
export { DataRow };
//=====[ GRID COMPONENT ]=============================================================================================================================
let GridComponent = class GridComponent {
constructor(_differs, _changeDetectorRef) {
this._differs = _differs;
this._changeDetectorRef = _changeDetectorRef;
this.events$ = new EventEmitter();
this.data = [];
this.onDestroy = new Subject();
this.viewChange = new BehaviorSubject({ start: 0, end: Number.MAX_VALUE });
this.gridDefaults = new GridDefaults();
}
get dataSource() {
return this._dataSource;
}
set dataSource(dataSource) {
if (this._dataSource !== dataSource) {
this.switchDataSource(dataSource);
}
}
toggleRowExpander(index) {
try {
this.dataRows.toArray()[index].toggleExpander();
}
catch (error) {
console.log(error);
}
}
emit(event) {
if (event.type == GridEventType.RowClicked) {
this.events$.emit(event);
let clickedDataRow = event.data;
let isCurrentselected = false;
this.dataRows.forEach((dataRow) => {
if (dataRow.isSelected()) {
if (dataRow == clickedDataRow) {
isCurrentselected = true;
}
// first we deselect it
dataRow.deselectRow();
// then we notify
this.events$.emit({
type: GridEventType.RowDeselected,
data: dataRow
});
}
});
if (!isCurrentselected) {
clickedDataRow.selectRow();
this.events$.emit({
type: GridEventType.RowSelected,
data: clickedDataRow
});
}
}
//console.log(`Grid Event ${GridEventType[event.type]}:`, event);
this.events$.emit(event);
}
ngOnInit() {
// create the columns differ to track changes to the column array
this.columnsDiffer = this._differs.find(this.model.columns).create();
this.dataDiffer = this._differs.find([]).create();
this.model.grid = this;
}
ngAfterContentInit() {
// make sure that all the column override/default templates/formatters are applied
this.gridDefaults.applyDefaults(this.model.columns);
// do the initial diff so that the next one will show any changes when doing the next diff
this.columnsDiffer.diff(this.model.columns);
// ok, lets setup/render the header row
this.setupHeader();
this.observeModel();
this.observeDataSource();
}
ngAfterContentChecked() {
}
ngAfterViewInit() {
//this.toggleRowExpander(this.model.config.expandRowIndex);
//console.log("GridComponent: ngAfterViewInit");
//this.model.grid = this;
this.emit({
type: GridEventType.Initialized,
data: this.model
});
}
ngAfterViewChecked() {
//this.toggleRowExpander(this.model.config.expandRowIndex);
this._changeDetectorRef.detectChanges();
}
ngOnChanges(changes) {
//console.log("GridComponent: ngOnChanges", this.model);
}
ngOnDestroy() {
this.onDestroy.next();
this.onDestroy.complete();
if (this.dataSource) {
this.dataSource.disconnect(this);
}
// clean up the subscription to the grid model when we are destroyed
if (this.modelSubscription) {
this.modelSubscription.unsubscribe();
this.modelSubscription = null;
}
}
setupHeader() {
// lets clear the row outlet container to make sure everything is squeeky clean
this._headerRowOutlet.viewContainer.clear();
// render the template that contains the header row component
this._headerRowOutlet.viewContainer.createEmbeddedView(this._headerRowDef.templateRef, { $implicit: this.model });
}
gridModelChanged(event) {
// always apply defaults (default data and header formatter if none specified)
this.gridDefaults.applyDefaults(this.model.columns);
// first we do the diff to get the changes (if any)
let changes = this.columnsDiffer.diff(this.model.columns);
//@todo - need a way to update columns - could basically just add
/*if (event && event.type == GridModelEventType.UPDATE){
// if this is an update
this.columnsDiffer.diff([]);
changes = this.columnsDiffer.diff(this.model.columns);
this.headerRow.clearCells();
}*/
// tell header row to look at the changes to insert/update/remove where required
this.headerRow.applyColumnChanges(changes);
this.dataRows.forEach((dataRow, index) => {
dataRow.applyColumnChanges(changes);
});
// make sure that our component is checked for any other changes
this._changeDetectorRef.markForCheck();
}
dataSourceDataChanged() {
const changes = this.dataDiffer.diff(this.data);
if (!changes) {
return;
}
// remove
changes.forEachRemovedItem((record) => {
//console.log("removing existing row", record);
this._dataRowOutlet.viewContainer.remove(record.previousIndex);
this.emit({
type: GridEventType.RowRemoved,
data: record
});
});
// add, insert
changes.forEachAddedItem((record) => {
//console.log("adding/inserting new row", record);
let rowContext = {
data: record.item,
model: this.model,
expanded: false
};
this._dataRowOutlet.viewContainer.createEmbeddedView(this._dataRowDef.templateRef, { $implicit: rowContext }, record.currentIndex);
this.emit({
type: GridEventType.RowAdded,
data: record
});
});
//@Todo - not the right place - just a temporary work around
this.emit({
type: GridEventType.Reloaded,
data: this.data
});
// we need to wait one tick for the rows to be rendered before trying to toggle them
setTimeout(() => {
// we just want to do this once. We can always call the toggleExpander manually but you would have to do it after the data has been loaded
if (this.model.config.expandRowIndex > -1) {
this.toggleRowExpander(this.model.config.expandRowIndex);
this.model.config.expandRowIndex = -1;
}
}, 0);
// then tell Angular to do it's checks
this._changeDetectorRef.markForCheck();
}
switchDataSource(dataSource) {
this.data = [];
if (this._dataSource) {
this._dataSource.disconnect(this);
}
// Stop listening for data from the previous data source.
if (this.dataSubscription) {
this.dataSubscription.unsubscribe();
this.dataSubscription = null;
}
this._dataSource = dataSource;
}
observeModel() {
this.modelSubscription = this.model._changes.subscribe((event) => {
this.gridModelChanged(event);
});
}
observeDataSource() {
if (this.dataSource && !this.dataSubscription) {
this.dataSubscription = takeUntil.call(this.dataSource.connect(this), this.onDestroy).subscribe(data => {
this.data = data;
this.dataSourceDataChanged();
});
}
}
};
GridComponent.ctorParameters = () => [
{ type: IterableDiffers },
{ type: ChangeDetectorRef }
];
tslib_1.__decorate([
Output('events'),
tslib_1.__metadata("design:type", Object)
], GridComponent.prototype, "events$", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", GridModel)
], GridComponent.prototype, "model", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", DataSource),
tslib_1.__metadata("design:paramtypes", [DataSource])
], GridComponent.prototype, "dataSource", null);
tslib_1.__decorate([
ViewChild(HeaderRowOutlet, { static: true }),
tslib_1.__metadata("design:type", HeaderRowOutlet)
], GridComponent.prototype, "_headerRowOutlet", void 0);
tslib_1.__decorate([
ViewChild(HeaderRowDef, { static: true }),
tslib_1.__metadata("design:type", HeaderRowDef)
], GridComponent.prototype, "_headerRowDef", void 0);
tslib_1.__decorate([
ViewChild('headerRow', { static: true }),
tslib_1.__metadata("design:type", TemplateRef)
], GridComponent.prototype, "headerRowTemplate", void 0);
tslib_1.__decorate([
ViewChild(HeaderRow, { static: false }),
tslib_1.__metadata("design:type", HeaderRow)
], GridComponent.prototype, "headerRow", void 0);
tslib_1.__decorate([
ViewChild(DataRowOutlet, { static: true }),
tslib_1.__metadata("design:type", DataRowOutlet)
], GridComponent.prototype, "_dataRowOutlet", void 0);
tslib_1.__decorate([
ViewChild(DataRowDef, { static: true }),
tslib_1.__metadata("design:type", DataRowDef)
], GridComponent.prototype, "_dataRowDef", void 0);
tslib_1.__decorate([
ViewChildren(DataRow),
tslib_1.__metadata("design:type", QueryList)
], GridComponent.prototype, "dataRows", void 0);
GridComponent = tslib_1.__decorate([
Component({
selector: 'am-data-grid',
template: `
<div class="am-grid">
<ng-container headerRowOutlet></ng-container>
<ng-container dataRowOutlet></ng-container>
<ng-container>
<header-row *headerRowDef="let model" [model]="model" (events)="emit($event)"></header-row>
<data-row *dataRowDef="let row" [row]="row" (events)="emit($event)"></data-row>
</ng-container>
</div>
`,
encapsulation: ViewEncapsulation.None
}),
tslib_1.__metadata("design:paramtypes", [IterableDiffers,
ChangeDetectorRef])
], GridComponent);
export { GridComponent };
export var GridEventType;
(function (GridEventType) {
GridEventType[GridEventType["RowExpanded"] = 0] = "RowExpanded";
GridEventType[GridEventType["RowContracted"] = 1] = "RowContracted";
GridEventType[GridEventType["RowRemoved"] = 2] = "RowRemoved";
GridEventType[GridEventType["RowAdded"] = 3] = "RowAdded";
GridEventType[GridEventType["Reloaded"] = 4] = "Reloaded";
GridEventType[GridEventType["ColumnRemoved"] = 5] = "ColumnRemoved";
GridEventType[GridEventType["ColumnAdded"] = 6] = "ColumnAdded";
GridEventType[GridEventType["DataChange"] = 7] = "DataChange";
GridEventType[GridEventType["Initialized"] = 8] = "Initialized";
GridEventType[GridEventType["RowClicked"] = 9] = "RowClicked";
GridEventType[GridEventType["RowSelected"] = 10] = "RowSelected";
GridEventType[GridEventType["RowDeselected"] = 11] = "RowDeselected";
})(GridEventType || (GridEventType = {}));
export var GridModelEventType;
(function (GridModelEventType) {
GridModelEventType[GridModelEventType["ADD"] = 0] = "ADD";
GridModelEventType[GridModelEventType["REMOVE"] = 1] = "REMOVE";
GridModelEventType[GridModelEventType["UPDATE"] = 2] = "UPDATE";
})(GridModelEventType || (GridModelEventType = {}));
export class GridModel {
constructor(config, styles = {}) {
this.columns = [];
this._changes = new Subject();
this.config = {
selection: !_.isNil(config.selection) ? config.selection : false,
showExpander: !_.isNil(config.showExpander) ? config.showExpander : false,
expanderFormatter: !_.isNil(config.expanderFormatter) ? config.expanderFormatter : null,
expanderTemplate: !_.isNil(config.expanderTemplate) ? config.expanderTemplate : null,
expandRowIndex: config.expandRowIndex
};
this.styles = {
containerClasses: !_.isNil(styles.containerClasses) ? styles.containerClasses : [],
gridClasses: !_.isNil(styles.containerClasses) ? styles.containerClasses : [],
scrollX: !_.isNil(styles.scrollX) ? styles.scrollX : false,
minColumnWidth: !_.isNil(styles.minColumnWidth) ? styles.minColumnWidth : null,
dataRowStyleResolver: styles.dataRowStyleResolver || null
};
}
toggleExpander(index) {
this.grid.toggleRowExpander(index);
}
addColumn(column) {
column.model = this;
this.columns.push(column);
this.notifyChanges(GridModelEventType.ADD);
}
getColumnByKey(key) {
return _.find(this.columns, { config: { key: key } });
}
insertColumn(column, index) {
//column.model = this;
this.columns.splice(index, 0, column);
this.notifyChanges(GridModelEventType.ADD);
}
removeColumn(column) {
this.columns = _.without(this.columns, column);
this.notifyChanges(GridModelEventType.REMOVE);
}
removeColumnByIndex(index) {
this.columns.splice(index, 1);
this.notifyChanges(GridModelEventType.REMOVE);
}
removeColumnsByKey(key) {
_.remove(this.columns, (column) => {
return column.config.key == key;
});
this.notifyChanges(GridModelEventType.REMOVE);
}
updateStyles() {
this.notifyChanges(GridModelEventType.UPDATE, null);
}
updateColumn(column) {
let index = this.columns.indexOf(column);
if (index > -1) {
this.columns[index] = column;
}
this.notifyChanges(GridModelEventType.UPDATE, column);
}
removeAll() {
this.columns = [];
this.notifyChanges(GridModelEventType.REMOVE);
}
notifyChanges(type, column) {
this._changes.next({
type: type,
column: column,
columns: this.columns
});
}
}
export class GridColumn {
constructor(config, styles = {}, options = {}) {
this.refresh = false;
this.config = {
key: config.key,
type: config.type || 'text',
heading: config.heading,
sortable: !_.isNil(config.sortable) ? config.sortable : false,
noHeading: config.noHeading,
headingFormatter: config.headingFormatter || GridKeyHeaderFormatter,
formatter: config.formatter,
context: config.context || {},
headingTemplate: config.headingTemplate,
dataTemplate: config.dataTemplate
};
this.styles = {
headerCellStyleClasses: !_.isNil(styles.headerCellStyleClasses) ? styles.headerCellStyleClasses : [],
filterCellStyleClasses: !_.isNil(styles.filterCellStyleClasses) ? styles.filterCellStyleClasses : [],
dataCellStyleClasses: !_.isNil(styles.dataCellStyleClasses) ? styles.dataCellStyleClasses : [],
flex: !_.isNil(styles.flex) ? styles.flex : 1,
minWidth: !_.isNil(styles.minWidth) ? styles.minWidth : null,
maxWidth: !_.isNil(styles.maxWidth) ? styles.maxWidth : null,
dataCellStyleResolver: styles.dataCellStyleResolver || null
};
if (!this.config.heading && !this.config.noHeading) {
let tempHeading = this.config.key;
this.config.heading = '';
tempHeading.split('.').forEach((name, index) => {
this.config.heading += _.startCase(name) + ' ';
});
}
this.options = options;
}
}
let GridPropertyFormatter = class GridPropertyFormatter {
getValue() {
return _.get(this.row.data, this.column.config.key);
/*
try {
return eval(`this.row.data.${this.column.config.key}`);
} catch (error){
return null;
}
*/
}
};
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", GridColumn)
], GridPropertyFormatter.prototype, "column", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], GridPropertyFormatter.prototype, "row", void 0);
GridPropertyFormatter = tslib_1.__decorate([
Component({
template: `{{getValue()}}`
})
], GridPropertyFormatter);
export { GridPropertyFormatter };
let GridDateFormatter = class GridDateFormatter extends GridPropertyFormatter {
constructor(gridDateFormat) {
super();
this.gridDateFormat = gridDateFormat;
//console.log("=======================***> ", this.gridDateFormat);
if (!gridDateFormat) {
//console.log("DHO!!@ ", this.gridDateFormat);
this.gridDateFormat = {
format: 'fullDate'
};
}
}
getFormat() {
return this.column.options.dateFormat || this.gridDateFormat.format;
}
};
GridDateFormatter.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [AM_GRID_DATE_FORMAT,] }] }
];
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", GridColumn)
], GridDateFormatter.prototype, "column", void 0);
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", Object)
], GridDateFormatter.prototype, "row", void 0);
GridDateFormatter = tslib_1.__decorate([
Component({
template: `{{getValue() || '' | date : getFormat()}}`
}),
tslib_1.__param(0, Optional()), tslib_1.__param(0, Inject(AM_GRID_DATE_FORMAT)),
tslib_1.__metadata("design:paramtypes", [Object])
], GridDateFormatter);
export { GridDateFormatter };
let GridKeyHeaderFormatter = class GridKeyHeaderFormatter {
};
tslib_1.__decorate([
Input(),
tslib_1.__metadata("design:type", GridColumn)
], GridKeyHeaderFormatter.prototype, "column", void 0);
GridKeyHeaderFormatter = tslib_1.__decorate([
Component({
template: `{{column.config.heading}}`
})
], GridKeyHeaderFormatter);
export { GridKeyHeaderFormatter };
//=====[ GRID DEFAULTS ]==============================================================================================================================
export class GridDefaults {
constructor() {
this.columns = new Map();
let dateCol = new GridColumn({
type: 'date',
key: 'date',
formatter: GridDateFormatter
}, {}, {
//dateFormat: 'fullDate'
});
let textCol = new GridColumn({ type: 'text', key: 'text', formatter: GridPropertyFormatter });
this.setDefaultColumn(dateCol.config.type, dateCol);
this.setDefaultColumn(textCol.config.type, textCol);
}
setDefaultColumn(type, column) {
this.columns.set(type, column);
}
getDefaultColumn(type) {
return this.columns.get(type);
}
applyDefaults(columns) {
if (!columns || columns.length == 0) {
return;
}
columns.forEach((column, index) => {
let defaultColumn = this.getDefaultColumn(column.config.type);
if (defaultColumn) {
_.defaultsDeep(column, defaultColumn);
//console.log(column);
}
});
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BiaTgvYW0tZGF0YS10YWJsZS8iLCJzb3VyY2VzIjpbImFwcC9tb2R1bGVzL2FtLWRhdGEtdGFibGUvZ3JpZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixnQkFBZ0IsRUFDaEIsZ0JBQWdCLEVBQ2hCLGFBQWEsRUFDYix1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCx3QkFBd0IsRUFDeEIsU0FBUyxFQUNULFVBQVUsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUN4RSxLQUFLLEVBQ0wsb0JBQW9CLEVBQ3BCLGVBQWUsRUFDZixjQUFjLEVBQ2QsZUFBZSxFQUNmLFNBQVMsRUFDVCxTQUFTLEVBQ1QsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQ3hCLFNBQVMsRUFDVCxTQUFTLEVBQ1QsWUFBWSxFQUNaLGFBQWEsRUFDYixXQUFXLEVBQ1gsSUFBSSxFQUNKLFNBQVMsRUFDVCxZQUFZLEVBQ1osZ0JBQWdCLEVBQ2hCLGlCQUFpQixFQUNsQixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sY0FBYyxDQUFDO0FBRXJDLE9BQU8sRUFBbUIsVUFBVSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDdEUsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBRXJELE9BQU8sS0FBSyxDQUFDLE1BQU0sUUFBUSxDQUFDO0FBQzVCLE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQU1sRCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FDOUIsSUFBSSxjQUFjLENBQWlCLHFCQUFxQixDQUFDLENBQUM7QUFFNUQsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQW1CO0lBQ2xELE1BQU0sRUFBRSxVQUFVO0NBQ25CLENBQUM7QUFHRixzSkFB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