UNPKG

@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
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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