sdk-datagrid
v2.2.19
Published
Customizable (Angular) datagrid with data options for manipulation, and charts for visualization.
Downloads
935
Maintainers
Readme
Description:
The sdk-datagrid component is a mobile-friendly, fully-functional data grid that gives the developer complete control over the processing and appearance of the data. From a simple table to a complex, customizable (Excel-like) spreadsheet, this component adds so much power to any application.
NOTE: This package leverages the sdk-core-library for core configurations (i.e., colors, icons, etc.).
INSTALLATION:
Using NPM:
npm install --save sdk-datagrid
CONFIGURATION:
To configure the sdk-datagrid
for your application, add the following lines to your app.module.ts file:
import { SDKDatagridModule } from 'sdk-datagrid';
@NgModule({
imports: [
SDKDatagridModule
]
})
export class AppModule { }
PROPERTIES:
/**************************************************************************
* Input/Output Parameters for updating the Grid
**************************************************************************/
@Input() updateGrid: boolean = false; // Applies changes/data to the grid.
@Output() updateGridChange = new EventEmitter<boolean>(); // Callback to set updateGrid variable.
/**************************************************************************
* Input/Output Parameters for editing a record
**************************************************************************/
@Input() editRecordIndex: number | null | undefined; // The record that is currently being edited.
@Output() editRecordIndexChange = new EventEmitter<number | null | undefined>(); // Callback to set editRecordIndex variable.
/**************************************************************************
* Input/Output Parameters for dataset change
**************************************************************************/
@Input() datasets: string[] = []; // List of datasets.
@Input() activeDataset: string = ""; // The current selected dataset.
@Output() activeDatasetChange = new EventEmitter<string>(); // Callback to set activeDataset variable.
/**************************************************************************
* Input/Output Parameters for updating columns
**************************************************************************/
@Input() columns: SDKDataGridColumn[] = []; // The columns to be used for the grid.
@Input() columnHeaderStyle: string = ""; // Style used for column headers.
@Output() columnsChange = new EventEmitter<SDKDataGridColumn[]>(); // Callback to set columns variable.
/**************************************************************************
* Input Parameters for rows
**************************************************************************/
@Input() detailTemplate!: TemplateRef<any>; // Embedded component for row detail.
/**************************************************************************
* Input/Output Parameters for updating custom filters
**************************************************************************/
@Input() customFilters: SDKDataGridCustomFilter[] = []; // Custom filters added to standard filter provided in loaddata callback (filters).
@Output() customFiltersChange = new EventEmitter<SDKDataGridCustomFilter[]>(); // Callback to set custom filters variable.
/**************************************************************************
* Input/Output Parameters for exporting data
**************************************************************************/
@Input() dataExport: any = ""; // The data to export.
@Output() dataExportChange = new EventEmitter<any>(); // Callback to set dataExport variable.
/**************************************************************************
* Input/Output Parameters for settings data
**************************************************************************/
@Input() settings: SDKDataGridSettings[] = []; // Options that are saved outside the grid. This value should be set to the value retieved from the datagrid @Output method "settingsSavedEvent". Consider it a passthrough value.
@Input() clearSettingsCache: boolean = false; // Clears any grid storage of settings.
@Output() savedSettingsEvent: EventEmitter<SDKDataGridSettings[]> = new EventEmitter(); // Used as a callback to save settings.
@Output() clearSettingsCacheChange = new EventEmitter<boolean>(); // Callback to set clearSettingsCache variable.
/**************************************************************************
* Required Output Parameters
**************************************************************************/
@Output() loadDataEvent = new EventEmitter<any>(); // Callback with grid changes.
/**************************************************************************
* Optional Input/Output Parameters
**************************************************************************/
@Input() name: string = ""; // Unique name of the grid (per page).
@Input() title: string = ""; // Title of the grid.
@Input() titleStyle: string = ""; // Style used for title.
@Input() options: SDKDataGridOptions | undefined; // Grid options.
@Input() fontFamily: string = ""; // font-family used for grid.
@Input() data: any = ""; // The data to display in the grid.
@Input() rowValues: number[] = [10, 25, 50, 100, 500, 1000]; // Sets the values used for records per page.
@Input() defaultRows: number = 100; // Default value for records per page.
@Input() rows: number | undefined; // Current rows in dataset.
@Input() page: number | undefined; // Current page of dataset.
@Input() total: number | undefined; // Total records in dataset.
@Output() saveGridDataEvent: EventEmitter<any> = new EventEmitter(); // Callback for saving changes to data.
@Output() deleteGridDataEvent: EventEmitter<any> = new EventEmitter(); // Callback for saving changes to data.
@Output() selectedRowActionEvent: EventEmitter<any> = new EventEmitter(); // // Callback for row actions. NOTE: The return object is { record: [the record], index: [the record index] }
/**************************************************************************
* Processing Parameters
**************************************************************************/
@Input() error: string = ""; // Any errors that occur during processing.
@Input() isDebug: boolean = false; // Turns on debugging.
USAGE:
Basic Setup
<sdk-datagrid
[(updateGrid)]="updateGrid"
[(columns)]="columns"
[data]="data"
[rows]="rows"
[page]="page"
[total]="total"
[error]="error"
(loadDataEvent)="loadData($event)">
</sdk-datagrid>
.ts file
public updateGrid: boolean = false; // Required 2-way binding.
public columns: SDKDataGridColumn[] = []; // Required 2-way binding.
public data: any;
public rows: number | undefined;
public page: number | undefined;
public total: number | undefined;
public error: string = "";
// Callback function for loading data (required).
public async loadData(event: any = null) {
this.isLoading = true;
let body: string = this.buildBody(event);
try {
await this.httpService.Post(dataSource, body).then((data: any) => {
if (data) {
this.data = data["Data"];
this.rows = parseInt(data["Rows"]);
this.page = parseInt(data["Page"]);
this.total = parseInt(data["Total"]);
this.error = data["Error"];
setTimeout(() => {
this.updateGrid = true; // Tell the grid to update.
}, 100);
}
});
} catch (error: any) {
this.error = error.message;
}
this.isLoading = false;
}
// Change the body parameters to fit your API call.
private buildBody(event: any = null): string {
let sorts: any = [];
let filters: any = [];
let formulas: any = [];
this.column.forEach((column: SDKDataGridColumn) => {
if (column.Sort) {
sorts.push({ ColumnName: column.Name, Direction: column.Sort.direction, Position: column.Sort.position });
}
if (column.Filter) {
let filtersOperation = Object.keys(Filters)[Object.values(Filters).indexOf(column.Filter.operation[0].toString())];
filters.push({ ColumnName: column.Name, Operation: filtersOperation, Value: column.Filter.value });
}
if (column.Formulas) {
let formulaOperation = Object.keys(FormulaOperation)[Object.values(FormulaOperation).indexOf(column.Formulas.operation.toString())];
formulas.push({ ColumnName: column.Name, Operation: formulaOperation, Format: column.Formulas.format });
}
});
let parameters: any = {
rows: event.rows,
page: event.page,
sorts: sorts,
filters: filters,
formulas: formulas
};
return JSON.stringify(parameters);
}
Columns
If you want to specify the columns, define them using the SDKDataGridColumn
object.
.ts file
@ViewChild('category') category!: TemplateRef<any>;
@ViewChild('dataTemplate') dataTemplate!: TemplateRef<any>;
@ViewChild('actionRight') actionRight!: TemplateRef<any>;
@ViewChild('detailTemplate') detailTemplate!: TemplateRef<any>;
public updateGrid: boolean = false;
public editRecordIndex: number | null | undefined = null;
public columns: SDKDataGridColumn[] = [
{ Name: 'category', DisplayName: 'Category', required: true, style: 'color: red', notes: 'MUST be a valid Category.', editTemplate: () => this.category },
{ Name: 'air_date', DisplayName: 'Date', required: true, validCharacters: 'calendar', pattern: 'YYYY-MM-DD' },
{ Name: 'question', DisplayName: 'Question', isVisible: false, height: '50px', width: '100px', dataTemplate: () => this.dataTemplate },
{ Name: 'value', DisplayName: 'Value', required: true, notes: 'Between 100 - 1000.', validCharacters: 'numeric' },
{ Name: 'answer', DisplayName: 'Answer', dataTemplate: () => this.dataTemplate },
{ Name: 'round', DisplayName: 'Round' },
{ Name: 'show_number', DisplayName: 'Show', validCharacters: 'custom', pattern: '^[0-9]{4}$' },
{ Name: 'fin', DisplayName: 'Completed' },
{ Name: 'Edit', DisplayName: 'Edit', dataTemplate: () => this.actionRight }
];
public data: any;
public rows: number | undefined;
public page: number | undefined;
public total: number | undefined;
public error: string = "";
// If editing is enabled...
public editData(index: any) {
this.editRecordIndex = index;
}
public saveData(index: number, record: any) {
// Update the record as a whole.
let dataIndex = ((this.page ?? 1) - 1) * (this.rows ?? 0) + index;
this.data[dataIndex] = { ...record };
// Update each column in the record.
for (let key in this.data[dataIndex]) {
if (Object.prototype.hasOwnProperty.call(activeRow, key)) {
this.data[index][key] = record[key];
}
}
// Save to database and show message.
// Reload data.
}
public cancelData() {
this.editRecordIndex = null;
this.updateGrid = true; // Tell grid to update.
}
.html file
<sdk-datagrid
[(updateGrid)]="updateGrid"
[(columns)]="columns"
[(editRecordIndex)]="editRecordIndex"
[data]="data"
[rows]="rows"
[page]="page"
[total]="total"
[error]="error"
[detailTemplate]="detailTemplate"
(loadDataEvent)="loadData($event)">
</sdk-datagrid>
<ng-template #category let-index="index" let-record="record">
<div>
<select style="margin-left: 10px;">
<option value="">...</option>
<option value="HISTORY">HISTORY</option>
<option value="3-LETTER WORDS">3-LETTER WORDS</option>
<option value="THE COMPANY LINE">THE COMPANY LINE</option>
<option value="EPITAPHS & TRIBUTES">EPITAPHS & TRIBUTES</option>
<option value="ESPN's TOP 10 ALL-TIME ATHLETES">ESPN's TOP 10 ALL-TIME ATHLETES</option>
</select>
</div>
</ng-template>
<ng-template #dataTemplate let-value="value">
<div>{{ value }}</div>
</ng-template>
<ng-template #actionRight let-index="index" let-record="record" let-column="column" let-value="value">
<div *ngIf="index !== editRecordIndex">
<div title="Edit" class="icon cursor" (click)="editData(index)">edit</div>
<div title="Delete" class="icon cursor delete">delete</div>
</div>
<div *ngIf="index === editRecordIndex">
<div title="Save" class="icon cursor done" (click)="saveData(index, record)">done</div>
<div title="Cancel" class="icon cursor delete" (click)="cancelData()">close</div>
</div>
</ng-template>
<ng-template #detailTemplate let-index="index" let-record="record">
<div style="color: blue; cursor: pointer;">{{ record["question"] }}</div>
</ng-template>
Exporting Data
<sdk-datagrid
[(updateGrid)]="updateGrid"
[(columns)]="columns"
[(dataExport)]="dataExport"
[data]="data"
[rows]="rows"
[page]="page"
[total]="total"
[error]="error"
(loadDataEvent)="loadData($event)">
</sdk-datagrid>
.ts file
public updateGrid: boolean = false; // Required 2-way binding.
public columns: SDKDataGridColumn[] = []; // Required 2-way binding.
public dataExport: any; // Required 2-way binding for exporting.
public data: any;
public rows: number | undefined;
public page: number | undefined;
public total: number | undefined;
public error: string = "";
// Callback function for loading data (required).
public async loadData(event: any = null) {
this.isLoading = true;
let body: string = this.buildBody(event);
// The "event" will contain "Export Data" ONLY if the "Include all data" option has
// been selected in the Export window. If so, this indicates you want to export ALL
// your data without filtering or sorting. Basically, clearing out the "body" parameter
// removes the filtering and sorting requirements. If that option is NOT selected,
// the exporting is handled within the sdk-datagrid based on the current "data" value.
if (event && event.action === "Export Data") {
body = "";
}
try {
await this.httpService.Post(dataSource, body).then((data: any) => {
if (data) {
if (event && event.action === "Export Data") {
this.dataExport = data["Data"];
this.isLoading = false;
} else {
this.data = data["Data"];
this.rows = parseInt(data["Rows"]);
this.page = parseInt(data["Page"]);
this.total = parseInt(data["Total"]);
this.error = data["Error"];
setTimeout(() => {
this.updateGrid = true; // Tell the grid to update.
}, 100);
}
}
});
} catch (error: any) {
this.error = error.message;
}
this.isLoading = false;
}
// Change the body parameters to fit your API call.
private buildBody(event: any = null): string {
let sorts: any = [];
let filters: any = [];
let formulas: any = [];
this.column.forEach((column: SDKDataGridColumn) => {
if (column.Sort) {
sorts.push({ ColumnName: column.Name, Direction: column.Sort.direction, Position: column.Sort.position });
}
if (column.Filter) {
let filtersOperation = Object.keys(Filters)[Object.values(Filters).indexOf(column.Filter.operation[0].toString())];
filters.push({ ColumnName: column.Name, Operation: filtersOperation, Value: column.Filter.value });
}
if (column.Formulas) {
let formulaOperation = Object.keys(FormulaOperation)[Object.values(FormulaOperation).indexOf(column.Formulas.operation.toString())];
formulas.push({ ColumnName: column.Name, Operation: formulaOperation, Format: column.Formulas.format });
}
});
let parameters: any = {
rows: event.rows,
page: event.page,
sorts: sorts,
filters: filters,
formulas: formulas
};
return JSON.stringify(parameters);
}
Custom Options
If you want to add a custom option to the sdk-datagrid
, use the optionAddons/windowAddons
parameters. First, create your "custom" option and window components.
mycustom-option.component
.html file
<div (click)="showDataOptions('myCustom')">
<div title="My Custom Option" class="sdk-icon" [ngClass]="optionTitle === 'myCustom' ? 'active' : ''">file_download</div>
<div *ngIf="myCustomBadge !== ''" class="badge">
<div class="label">{{ myCustomBadge }}</div>
</div>
</div>
.ts file
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'mycustom-option',
templateUrl: './mycustom-option.component.html',
styleUrls: ['./mycustom-option.component.scss']
})
export class MyCustomOptionComponent {
@Input() optionTitle: string = ""; // Unique name for option.
@Output() showDataOptionsEvent = new EventEmitter<any>(); // Method to show option window.
public myCustomBadge: string = ""; // Used to add badge to custom option.
public showDataOptions(type: string) {
this.showDataOptionsEvent.emit(type);
}
}
mycustom-window.component
.html file
<div *ngIf="dataClass === 'expand' && optionTitle === 'mycustom'" class="sdk-datagrid-window">
<div class="header">
<span class="title">My Custom Option</span>
<span title="Close" class="sdk-icon close" (click)="close()">close</span>
</div>
<div class="actions">
// Add your custom actions here (if applicable).
</div>
<div class="content">
// Add your custom option functionality here.
</div>
<div class="footer">
<button class="button" type="button" (click)="apply()">Apply</button>
</div>
</div>
.ts file
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { SDKDataGridColumn } from 'sdk-datagrid';
@Component({
selector: 'mycustom-window',
templateUrl: './mycustom-window.component.html',
styleUrls: ['./mycustom-window.component.scss']
})
export class MyCustomWindowComponent {
@Input() dataClass: string = ""; // Used to indicate if window is open/closed.
@Input() optionTitle: string = ""; // Unique name for option.
@Input() datasets: any[] = []; // Data array.
@Input() columns: SDKDataGridColumn[] = []; // Columns defines for data.
@Input() filters: any[] = []; // Filters defines for data.
@Input() sorts: any[] = []; // Sorting defines for data.
@Output() applyEvent = new EventEmitter<any>(); // Apply option.
@Output() closeEvent = new EventEmitter<any>(); // Close window.
public close() {
this.closeEvent.emit();
}
public async apply() {
this.applyEvent.emit();
this.closeEvent.emit();
}
}
Then add those components to your datagrid.
.ts file
import { MyCustomOptionComponent } from './mycustom/option/mycustom-option.component';
import { MyCustomWindowComponent } from './mycustom/window/mycustom-window.component';
public myCustomOptionComponent = MyCustomOptionComponent;
public myCustomWindowComponent = MyCustomWindowComponent;
.html file
<sdk-datagrid
[(updateGrid)]="updateGrid"
[(columns)]="columns"
[data]="data"
[rows]="rows"
[page]="page"
[total]="total"
[optionAddons]="[myCustomOptionComponent]"
[windowAddons]="[myCustomWindowComponent]"
[error]="error"
(loadDataEvent)="loadData($event)">
</sdk-datagrid>
NOTES:
In order to update the grid, you MUST set the
updateGrid
property totrue
. The grid will automatically set it back tofalse
once the update is complete (hence the 2-way binding).To customize filtering for a column:
Define the
FilterTypes
andFilterValues
in the columns object.public columns: SDKDataGridColumn[] = [ { Name: 'category', DisplayName: 'Category', required: true, style: 'color: red', notes: 'MUST be a valid Category.', editTemplate: () => this.category }, { Name: 'air_date', DisplayName: 'Date', required: true, validCharacters: 'calendar', pattern: 'YYYY-MM-DD' }, { Name: 'question', DisplayName: 'Question', height: '50px', width: '100px', dataTemplate: () => this.dataTemplate }, { Name: 'value', DisplayName: 'Value', required: true, notes: 'Between 100 - 1000.', validCharacters: 'numeric' }, { Name: 'answer', DisplayName: 'Answer', dataTemplate: () => this.dataTemplate }, { Name: 'round', DisplayName: 'Round', FilterTypes: [ Filters.Equals ], FilterValues: [ 'Jeopardy!', 'Double Jeopardy!' ] }, { Name: 'show_number', DisplayName: 'Show', FilterTypes: [ Filters.LessThanOrEqual, Filters.GreaterThanOrEqual ], FilterValues: [ 4000, 4500, 5000 ], validCharacters: 'custom', pattern: '^[0-9]{4}$' }, { Name: 'fin', DisplayName: 'Completed', FilterTypes: [ Filters.Equals ], FilterValues: [ true, false ] }, { Name: 'Edit', DisplayName: 'Edit', actionSide: "right", dataTemplate: () => this.actionRight } ];
To use a multi-select dropdown as your filter, define the
FilterMultiSelect
andFilterValues
in the columns object.public columns: SDKDataGridColumn[] = [ { Name: 'category', DisplayName: 'Category', required: true, style: 'color: red', notes: 'MUST be a valid Category.', editTemplate: () => this.category }, { Name: 'air_date', DisplayName: 'Date', required: true, validCharacters: 'calendar', pattern: 'YYYY-MM-DD' }, { Name: 'question', DisplayName: 'Question', isVisible: false, height: '50px', width: '100px', dataTemplate: () => this.dataTemplate }, { Name: 'value', DisplayName: 'Value', required: true, notes: 'Between 100 - 1000.', validCharacters: 'numeric' }, { Name: 'answer', DisplayName: 'Answer', showSort: false, showFilter: false, dataTemplate: () => this.dataTemplate }, { Name: 'round', DisplayName: 'Round', FilterMultiSelect: true, FilterValues: [ 'Jeopardy!', 'Double Jeopardy!', 'Final Jeopardy!', 'Tiebreaker' ] }, { Name: 'show_number', DisplayName: 'Show', FilterTypes: [ Filters.GreaterThanOrEqual, Filters.LessThanOrEqual ], FilterValues: [ 4000, 4500, 5000, 6000 ] }, { Name: 'fin', DisplayName: 'Completed', FilterTypes: [ Filters.Equals ], FilterValues: [ true, false ]}, { Name: 'Edit', DisplayName: 'Edit', actionSide: "right", dataTemplate: () => this.actionRight } ];
To create custom filters (
SDKDataGridCustomFilter
), the following properties are available:public Name: string = ""; // Unique filter name. public DisplayName?: string = ""; // Name to display to user. public Type?: FilterType = FilterType.Textbox; // Type of filter (Textbox, TextboxOnly, Checkbox, Dropdown). public notes?: string = ""; // START: sdk-select properties for Dropdown filters. public FilterMultiSelect?: boolean = false; // Allows multiple filter values to be selected. public FilterTypes?: any[] = []; // Allows you to define specific filter types. NOTE: If FilterMultiSelect = true, this property is forced to [Filters.Equals, Filters.NotEquals]. public FilterValues?: any[] = []; // Allows you to define specific filter values. public Filter?: SDKDataGridFilter | null = null; // Values set for filter. public FilterValueDefault?: any; // Default value for Dropdown type. public setFilterValues?: () => Promise<any[]>; // Optional callback method to load filter values. // END: sdk-select properties for Dropdown filters. FilterType Enums: - Textbox - TextboxOnly - Checkbox - Dropdown
NOTE: If
Type = FilterType.Textbox
and is used withFilterTypes
, the custom filter will have an Operation/Value layout. IfFilterTypes
is NOT used, the layout will ONLY have a Value.To use columns (
SDKDataGridColumn
), the following properties are available:public Name: string = ""; // Original db name. public DisplayName?: string = ""; // System override of db name (Name). public FriendlyName?: string = ""; // User provides. Produces * indicator. public Sort?: SDKDataGridSort | null = null; // Sorting (asc/desc) applied to column data. public Filter?: SDKDataGridFilter | null = null; // Filters applied to column data. public Formulas?: any = null; // Formulas applied to column. public showSort?: boolean = true; // Allows you to turn on/off sorting capabilities. public showFilter?: boolean = true; // Allows you to turn on/off filtering capabilities. public showTooltip?: boolean = false; public isAction?: boolean = false; // Is the column associated to an action. public isVisible?: boolean = true; // Allows you to turn on/off the visibility of the column. public actionSide?: string = "right" // right or left // START: Filter properties public FilterMultiSelect?: boolean = false; // Allows multiple filter values to be selected. public FilterTypes?: any[] = []; // Allows you to define specific filter types. NOTE: If FilterMultiSelect = true, this property is forced to [Filters.Equals, Filters.NotEquals]. public FilterValues?: any[] = []; // Allows you to define specific filter values. public FilterType?: FilterType = FilterType.Textbox; // Type of filter (Textbox, TextboxOnly, Checkbox, Dropdown). public FilterValueDefault?: any; // Default value for Dropdown type. // END: Filter properties // START: editTemplate option public allowEdit?: boolean = true; public required?: boolean = false; public notes?: string = ""; public validCharacters?: string = ""; public hint?: string = ""; public pattern?: string = ""; public height?: string = ""; public width?: string = ""; public border?: string = ""; public style?: string = ""; // END: editTemplate option // Custom templates public headerTemplate?: () => TemplateRef<any>; public dataTemplate?: () => TemplateRef<any>; public editTemplate?: () => TemplateRef<any>; // Custom methods public formatData?: (value: any) => string; // Optional callback method to format the data. public setFilterValues?: () => Promise<any[]>; // Optional callback method to load filter values.
To use options (
SDKDataGridOptions
), the following properties are available:public header?: boolean = true; public footer?: boolean = true; public paging?: boolean = true; public options?: boolean = true; public datasetTabs?: boolean = false; public autoClosePanel?: boolean = true; public minimizeOptions?: boolean = false; public expandableRows?: boolean = false; public settings?: boolean = false; public columns?: boolean = true; public filters?: boolean = true; public sorts?: boolean = true; public formulas?: boolean = true; public charts?: boolean = false; public export?: boolean = true; public edit?: boolean = false; public delete?: boolean = true; public nowrap?: boolean = false; public settingsStorage?: StorageType = StorageType.Local;