@gp-grid/angular 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/fesm2022/gp-grid-angular.mjs +97 -4
- package/package.json +2 -2
- package/types/gp-grid-angular.d.ts +76 -3
package/README.md
CHANGED
|
@@ -73,6 +73,61 @@ Import the stylesheet once (e.g. in `styles.css` or `angular.json`):
|
|
|
73
73
|
|
|
74
74
|
For custom cell, edit, and header renderers, pass `ng-template` references via the column `cellRenderer` / `editRenderer` / `headerRenderer` fields — see the [Angular docs](https://www.gp-grid.io/docs/angular) for the full API.
|
|
75
75
|
|
|
76
|
+
## Dependency injection
|
|
77
|
+
|
|
78
|
+
For components that want lifecycle-managed cleanup or testable seams, use `provideGridData` and `injectGridData`. They wire the same mutable data source through Angular's DI, mirroring `useGridData` in `@gp-grid/react` and `@gp-grid/vue`. The service implements `OnDestroy` and clears the data source automatically when the component is destroyed.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { Component } from "@angular/core";
|
|
82
|
+
import {
|
|
83
|
+
GpGridComponent,
|
|
84
|
+
provideGridData,
|
|
85
|
+
injectGridData,
|
|
86
|
+
} from "@gp-grid/angular";
|
|
87
|
+
import type { AngularColumnDefinition } from "@gp-grid/angular";
|
|
88
|
+
|
|
89
|
+
interface Person {
|
|
90
|
+
id: number;
|
|
91
|
+
name: string;
|
|
92
|
+
age: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const initialRows: Person[] = [
|
|
96
|
+
{ id: 1, name: "Alice", age: 30 },
|
|
97
|
+
{ id: 2, name: "Bob", age: 25 },
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
@Component({
|
|
101
|
+
selector: "app-root",
|
|
102
|
+
standalone: true,
|
|
103
|
+
imports: [GpGridComponent],
|
|
104
|
+
providers: [
|
|
105
|
+
provideGridData<Person>({
|
|
106
|
+
getRowId: (row) => row.id,
|
|
107
|
+
initialData: initialRows,
|
|
108
|
+
}),
|
|
109
|
+
],
|
|
110
|
+
template: `
|
|
111
|
+
<gp-grid
|
|
112
|
+
[columns]="columns"
|
|
113
|
+
[dataSource]="grid.dataSource"
|
|
114
|
+
[rowHeight]="36" />
|
|
115
|
+
<button (click)="grid.addRows([{ id: 3, name: 'Carol', age: 28 }])">Add</button>
|
|
116
|
+
`,
|
|
117
|
+
})
|
|
118
|
+
export class App {
|
|
119
|
+
protected readonly grid = injectGridData<Person>();
|
|
120
|
+
|
|
121
|
+
protected readonly columns: AngularColumnDefinition[] = [
|
|
122
|
+
{ field: "id", cellDataType: "number", headerName: "ID", width: 80 },
|
|
123
|
+
{ field: "name", cellDataType: "text", headerName: "Name", width: 200 },
|
|
124
|
+
{ field: "age", cellDataType: "number", headerName: "Age", width: 100 },
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`provideGridData` returns a standard Angular `Provider[]`, so it composes with other `provide*` functions in the component's `providers` array. Register it on the consuming component (not on a parent injector) so each component instance gets its own data source.
|
|
130
|
+
|
|
76
131
|
## License
|
|
77
132
|
|
|
78
133
|
Apache-2.0 — see [LICENSE](./LICENSE).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, computed, TemplateRef, ChangeDetectionStrategy, Component, ViewChild, signal, effect, HostListener, inject, PLATFORM_ID } from '@angular/core';
|
|
2
|
+
import { input, output, computed, TemplateRef, ChangeDetectionStrategy, Component, ViewChild, signal, effect, HostListener, inject, PLATFORM_ID, InjectionToken, Injectable } from '@angular/core';
|
|
3
3
|
import { NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
|
|
4
4
|
import { isCellSelected, isCellActive, getFieldValue, formatCellValue, isCellInFillPreview, buildCellClasses, isCellEditing, calculateFilterPopupPosition, calculateScaledColumnPositions, getTotalWidth, calculateFillHandlePosition, DataSourceOwner, AutoScrollDriver, PendingRowDragController, InputEventAdapter, applyBatchInstructions, scrollCellIntoView, GridCore, createMutableClientDataSource } from '@gp-grid/core';
|
|
5
5
|
export { GridCore, createClientDataSource, createDataSourceFromArray, createMutableClientDataSource, createServerDataSource } from '@gp-grid/core';
|
|
@@ -941,7 +941,7 @@ class FilterPopupComponent {
|
|
|
941
941
|
this.updatePosition();
|
|
942
942
|
};
|
|
943
943
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: FilterPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
944
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: FilterPopupComponent, isStandalone: true, selector: "gp-grid-filter-popup", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, colIndex: { classPropertyName: "colIndex", publicName: "colIndex", isSignal: true, isRequired: true, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: true, transformFunction: null }, distinctValues: { classPropertyName: "distinctValues", publicName: "distinctValues", isSignal: true, isRequired: true, transformFunction: null }, currentFilter: { classPropertyName: "currentFilter", publicName: "currentFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply", close: "close" }, host: { listeners: { "keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "popupEl", first: true, predicate: ["popupEl"], descendants: true }], ngImport: i0, template: "\n<div\n #popupEl\n class=\"gp-grid-filter-popup\"\n [style.position]=\"'fixed'\"\n [style.zIndex]=\"10000\"\n [style.top.px]=\"popupTop()\"\n [style.left.px]=\"popupLeft()\"\n [style.minWidth.px]=\"popupMinWidth()\"\n [style.visibility]=\"positioned() ? 'visible' : 'hidden'\"\n (keydown.escape)=\"close.emit()\"\n (click)=\"$event.stopPropagation()\">\n\n <div class=\"gp-grid-filter-header\">\n Filter: {{ column().headerName ?? column().field }}\n </div>\n\n <div [class]=\"'gp-grid-filter-content ' + (isNumberColumn() ? 'gp-grid-filter-number' : 'gp-grid-filter-text')\">\n @if (isNumberColumn()) {\n @for (cond of numberConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setNumberNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setNumberNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onNumberOperatorChange(i, $any($event.target).value)\">\n @for (op of numberOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessNumberOp(cond.operator)) {\n <input\n type=\"number\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n @if (cond.operator === 'between') {\n <span class=\"gp-grid-filter-to\">to</span>\n <input\n type=\"number\"\n [value]=\"cond.valueTo\"\n (input)=\"cond.valueTo = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n }\n @if (numberConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeNumberCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addNumberCondition()\">\n + Add condition\n </button>\n } @else {\n @if (showValuesMode()) {\n <div class=\"gp-grid-filter-mode-toggle\">\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'values'\"\n (click)=\"filterMode = 'values'\">\n Values\n </button>\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'condition'\"\n (click)=\"filterMode = 'condition'\">\n Condition\n </button>\n </div>\n }\n\n @if (filterMode === 'values' && showValuesMode()) {\n <input\n class=\"gp-grid-filter-search\"\n type=\"text\"\n [value]=\"searchText\"\n (input)=\"searchText = $any($event.target).value\"\n placeholder=\"Search...\" />\n <div class=\"gp-grid-filter-actions\">\n <button type=\"button\" (click)=\"selectAll()\">Select All</button>\n <button type=\"button\" (click)=\"deselectAll()\">Deselect All</button>\n </div>\n <div class=\"gp-grid-filter-list\">\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"includeBlanks\"\n (change)=\"includeBlanks = $any($event.target).checked\" />\n <span class=\"gp-grid-filter-blank\">(Blanks)</span>\n </label>\n @for (entry of filteredUniqueEntries(); track entry.key) {\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"selectedValues.has(entry.key)\"\n (change)=\"toggleValue(entry.key, $any($event.target).checked)\" />\n <span>{{ entry.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (filterMode === 'condition') {\n @for (cond of textConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setTextNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setTextNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onTextOperatorChange(i, $any($event.target).value)\">\n @for (op of textOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessTextOp(cond.operator)) {\n <input\n class=\"gp-grid-filter-text-input\"\n type=\"text\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n @if (textConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeTextCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addTextCondition()\">\n + Add condition\n </button>\n }\n }\n\n <div class=\"gp-grid-filter-buttons\">\n <button type=\"button\" class=\"gp-grid-filter-btn-clear\" (click)=\"handleClear()\">\n Clear\n </button>\n <button type=\"button\" class=\"gp-grid-filter-btn-apply\" (click)=\"handleApply()\">\n Apply\n </button>\n </div>\n </div>\n</div>\n", isInline: true, changeDetection: i0.ChangeDetectionStrategy.
|
|
944
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: FilterPopupComponent, isStandalone: true, selector: "gp-grid-filter-popup", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, colIndex: { classPropertyName: "colIndex", publicName: "colIndex", isSignal: true, isRequired: true, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: true, transformFunction: null }, distinctValues: { classPropertyName: "distinctValues", publicName: "distinctValues", isSignal: true, isRequired: true, transformFunction: null }, currentFilter: { classPropertyName: "currentFilter", publicName: "currentFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply", close: "close" }, host: { listeners: { "keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "popupEl", first: true, predicate: ["popupEl"], descendants: true }], ngImport: i0, template: "\n<div\n #popupEl\n class=\"gp-grid-filter-popup\"\n [style.position]=\"'fixed'\"\n [style.zIndex]=\"10000\"\n [style.top.px]=\"popupTop()\"\n [style.left.px]=\"popupLeft()\"\n [style.minWidth.px]=\"popupMinWidth()\"\n [style.visibility]=\"positioned() ? 'visible' : 'hidden'\"\n (keydown.escape)=\"close.emit()\"\n (click)=\"$event.stopPropagation()\">\n\n <div class=\"gp-grid-filter-header\">\n Filter: {{ column().headerName ?? column().field }}\n </div>\n\n <div [class]=\"'gp-grid-filter-content ' + (isNumberColumn() ? 'gp-grid-filter-number' : 'gp-grid-filter-text')\">\n @if (isNumberColumn()) {\n @for (cond of numberConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setNumberNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setNumberNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onNumberOperatorChange(i, $any($event.target).value)\">\n @for (op of numberOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessNumberOp(cond.operator)) {\n <input\n type=\"number\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n @if (cond.operator === 'between') {\n <span class=\"gp-grid-filter-to\">to</span>\n <input\n type=\"number\"\n [value]=\"cond.valueTo\"\n (input)=\"cond.valueTo = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n }\n @if (numberConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeNumberCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addNumberCondition()\">\n + Add condition\n </button>\n } @else {\n @if (showValuesMode()) {\n <div class=\"gp-grid-filter-mode-toggle\">\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'values'\"\n (click)=\"filterMode = 'values'\">\n Values\n </button>\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'condition'\"\n (click)=\"filterMode = 'condition'\">\n Condition\n </button>\n </div>\n }\n\n @if (filterMode === 'values' && showValuesMode()) {\n <input\n class=\"gp-grid-filter-search\"\n type=\"text\"\n [value]=\"searchText\"\n (input)=\"searchText = $any($event.target).value\"\n placeholder=\"Search...\" />\n <div class=\"gp-grid-filter-actions\">\n <button type=\"button\" (click)=\"selectAll()\">Select All</button>\n <button type=\"button\" (click)=\"deselectAll()\">Deselect All</button>\n </div>\n <div class=\"gp-grid-filter-list\">\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"includeBlanks\"\n (change)=\"includeBlanks = $any($event.target).checked\" />\n <span class=\"gp-grid-filter-blank\">(Blanks)</span>\n </label>\n @for (entry of filteredUniqueEntries(); track entry.key) {\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"selectedValues.has(entry.key)\"\n (change)=\"toggleValue(entry.key, $any($event.target).checked)\" />\n <span>{{ entry.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (filterMode === 'condition') {\n @for (cond of textConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setTextNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setTextNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onTextOperatorChange(i, $any($event.target).value)\">\n @for (op of textOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessTextOp(cond.operator)) {\n <input\n class=\"gp-grid-filter-text-input\"\n type=\"text\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n @if (textConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeTextCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addTextCondition()\">\n + Add condition\n </button>\n }\n }\n\n <div class=\"gp-grid-filter-buttons\">\n <button type=\"button\" class=\"gp-grid-filter-btn-clear\" (click)=\"handleClear()\">\n Clear\n </button>\n <button type=\"button\" class=\"gp-grid-filter-btn-apply\" (click)=\"handleApply()\">\n Apply\n </button>\n </div>\n </div>\n</div>\n", isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
945
945
|
}
|
|
946
946
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: FilterPopupComponent, decorators: [{
|
|
947
947
|
type: Component,
|
|
@@ -949,7 +949,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
949
949
|
selector: 'gp-grid-filter-popup',
|
|
950
950
|
standalone: true,
|
|
951
951
|
imports: [],
|
|
952
|
-
changeDetection: ChangeDetectionStrategy.
|
|
952
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
953
953
|
template: FILTER_POPUP_TEMPLATE,
|
|
954
954
|
}]
|
|
955
955
|
}], ctorParameters: () => [], propDecorators: { popupEl: [{
|
|
@@ -1625,9 +1625,102 @@ const createGridData = (initialData, options) => {
|
|
|
1625
1625
|
};
|
|
1626
1626
|
};
|
|
1627
1627
|
|
|
1628
|
+
/**
|
|
1629
|
+
* Injection token holding the options passed to {@link provideGridData}.
|
|
1630
|
+
* Read internally by {@link GridDataService}; consumers should not depend on it directly.
|
|
1631
|
+
*/
|
|
1632
|
+
const GRID_DATA_OPTIONS = new InjectionToken("GRID_DATA_OPTIONS");
|
|
1633
|
+
/**
|
|
1634
|
+
* Angular service mirroring the React `useGridData` hook and the Vue
|
|
1635
|
+
* `useGridData` composable. Wraps `createMutableClientDataSource` with
|
|
1636
|
+
* automatic cleanup on component destroy.
|
|
1637
|
+
*
|
|
1638
|
+
* Provided per-component via {@link provideGridData}; injected via
|
|
1639
|
+
* {@link injectGridData} (or `inject(GridDataService)` with a manual cast).
|
|
1640
|
+
*/
|
|
1641
|
+
class GridDataService {
|
|
1642
|
+
dataSource;
|
|
1643
|
+
constructor() {
|
|
1644
|
+
const options = inject(GRID_DATA_OPTIONS);
|
|
1645
|
+
this.dataSource = createMutableClientDataSource(options.initialData, {
|
|
1646
|
+
getRowId: options.getRowId,
|
|
1647
|
+
debounceMs: options.debounceMs,
|
|
1648
|
+
useWorker: options.useWorker,
|
|
1649
|
+
parallelSort: options.parallelSort,
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1652
|
+
updateRow(id, data) {
|
|
1653
|
+
this.dataSource.updateRow(id, data);
|
|
1654
|
+
}
|
|
1655
|
+
addRows(rows) {
|
|
1656
|
+
this.dataSource.addRows(rows);
|
|
1657
|
+
}
|
|
1658
|
+
removeRows(ids) {
|
|
1659
|
+
this.dataSource.removeRows(ids);
|
|
1660
|
+
}
|
|
1661
|
+
updateCell(id, field, value) {
|
|
1662
|
+
this.dataSource.updateCell(id, field, value);
|
|
1663
|
+
}
|
|
1664
|
+
clear() {
|
|
1665
|
+
this.dataSource.clear();
|
|
1666
|
+
}
|
|
1667
|
+
getRowById(id) {
|
|
1668
|
+
return this.dataSource.getRowById(id);
|
|
1669
|
+
}
|
|
1670
|
+
getTotalRowCount() {
|
|
1671
|
+
return this.dataSource.getTotalRowCount();
|
|
1672
|
+
}
|
|
1673
|
+
flushTransactions() {
|
|
1674
|
+
return this.dataSource.flushTransactions();
|
|
1675
|
+
}
|
|
1676
|
+
ngOnDestroy() {
|
|
1677
|
+
this.dataSource.clear();
|
|
1678
|
+
}
|
|
1679
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GridDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1680
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GridDataService });
|
|
1681
|
+
}
|
|
1682
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GridDataService, decorators: [{
|
|
1683
|
+
type: Injectable
|
|
1684
|
+
}], ctorParameters: () => [] });
|
|
1685
|
+
/**
|
|
1686
|
+
* Typed convenience helper for `inject(GridDataService) as GridDataService<TData>`.
|
|
1687
|
+
*
|
|
1688
|
+
* @example
|
|
1689
|
+
* ```ts
|
|
1690
|
+
* @Component({
|
|
1691
|
+
* providers: [provideGridData<Person>({ getRowId: (r) => r.id, initialData: rows })],
|
|
1692
|
+
* })
|
|
1693
|
+
* export class MyGridComponent {
|
|
1694
|
+
* protected readonly grid = injectGridData<Person>();
|
|
1695
|
+
* }
|
|
1696
|
+
* ```
|
|
1697
|
+
*/
|
|
1698
|
+
const injectGridData = () => inject(GridDataService);
|
|
1699
|
+
|
|
1700
|
+
/**
|
|
1701
|
+
* Returns the providers needed to bind a {@link GridDataService} to the
|
|
1702
|
+
* current injector (typically a component's `providers` array). The service
|
|
1703
|
+
* is scoped to that injector — registering it on a parent injector would
|
|
1704
|
+
* silently share the underlying data source between children.
|
|
1705
|
+
*
|
|
1706
|
+
* @example
|
|
1707
|
+
* ```ts
|
|
1708
|
+
* @Component({
|
|
1709
|
+
* providers: [provideGridData<Person>({ getRowId: (r) => r.id, initialData: rows })],
|
|
1710
|
+
* })
|
|
1711
|
+
* export class MyGridComponent {
|
|
1712
|
+
* protected readonly grid = injectGridData<Person>();
|
|
1713
|
+
* }
|
|
1714
|
+
* ```
|
|
1715
|
+
*/
|
|
1716
|
+
const provideGridData = (options) => [
|
|
1717
|
+
{ provide: GRID_DATA_OPTIONS, useValue: options },
|
|
1718
|
+
GridDataService,
|
|
1719
|
+
];
|
|
1720
|
+
|
|
1628
1721
|
/**
|
|
1629
1722
|
* Generated bundle index. Do not edit.
|
|
1630
1723
|
*/
|
|
1631
1724
|
|
|
1632
|
-
export { FilterPopupComponent, GpGridComponent, GridBodyComponent, GridHeaderComponent, GridOverlaysComponent, createGridData };
|
|
1725
|
+
export { FilterPopupComponent, GRID_DATA_OPTIONS, GpGridComponent, GridBodyComponent, GridDataService, GridHeaderComponent, GridOverlaysComponent, createGridData, injectGridData, provideGridData };
|
|
1633
1726
|
//# sourceMappingURL=gp-grid-angular.mjs.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gp-grid/angular",
|
|
3
3
|
"description": "A high-performance Angular data grid component with virtual scrolling, cell selection, sorting, filtering, and Excel-like editing",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.13.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"module": "fesm2022/gp-grid-angular.mjs",
|
|
7
7
|
"typings": "types/gp-grid-angular.d.ts",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@angular/core": ">=18.0.0"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@gp-grid/core": "0.
|
|
54
|
+
"@gp-grid/core": "0.13.0",
|
|
55
55
|
"tslib": "^2.8.1"
|
|
56
56
|
},
|
|
57
57
|
"sideEffects": false,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { TemplateRef, ElementRef, AfterViewInit, OnDestroy, Signal, OnInit } from '@angular/core';
|
|
2
|
+
import { TemplateRef, ElementRef, AfterViewInit, OnDestroy, Signal, OnInit, InjectionToken, Provider } from '@angular/core';
|
|
3
3
|
import * as _gp_grid_core from '@gp-grid/core';
|
|
4
4
|
import { HeaderRendererParams, SortDirection, VisibleColumnInfo, HeaderData, ColumnDefinition, SlotData, CellPosition, CellRange, CellValue, CellRendererParams, EditRendererParams, FillHandlePosition, DragState, ColumnFilterModel, BatchChangeSetters, DataSource, RowId, HighlightingOptions, CellValueChangedEvent, ParallelSortOptions, MutableDataSource } from '@gp-grid/core';
|
|
5
5
|
export { CellDataType, CellPosition, CellRange, CellRendererParams, CellValue, CellValueChangedEvent, ColumnDefinition, ColumnFilterModel, DataSource, DataSourceRequest, DataSourceResponse, EditRendererParams, FilterCondition, FilterModel, GridCore, GridInstruction, HeaderRendererParams, HighlightContext, HighlightingOptions, MutableDataSource, RowId, SortDirection, SortModel, createClientDataSource, createDataSourceFromArray, createMutableClientDataSource, createServerDataSource } from '@gp-grid/core';
|
|
@@ -445,5 +445,78 @@ interface GridDataApi<TData> {
|
|
|
445
445
|
*/
|
|
446
446
|
declare const createGridData: <TData = unknown>(initialData: TData[], options: CreateGridDataOptions<TData>) => GridDataApi<TData>;
|
|
447
447
|
|
|
448
|
-
|
|
449
|
-
|
|
448
|
+
interface GridDataOptions<TData> {
|
|
449
|
+
/** Initial rows to seed the data source. */
|
|
450
|
+
initialData: TData[];
|
|
451
|
+
/** Function to extract a unique ID from each row. Required. */
|
|
452
|
+
getRowId: (row: TData) => RowId;
|
|
453
|
+
/** Debounce time for batching transactions in ms. Default 50. */
|
|
454
|
+
debounceMs?: number;
|
|
455
|
+
/** Use Web Worker for sorting large datasets (default: true) */
|
|
456
|
+
useWorker?: boolean;
|
|
457
|
+
/** Options for parallel sorting (only used when useWorker is true) */
|
|
458
|
+
parallelSort?: ParallelSortOptions | false;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Injection token holding the options passed to {@link provideGridData}.
|
|
462
|
+
* Read internally by {@link GridDataService}; consumers should not depend on it directly.
|
|
463
|
+
*/
|
|
464
|
+
declare const GRID_DATA_OPTIONS: InjectionToken<GridDataOptions<unknown>>;
|
|
465
|
+
/**
|
|
466
|
+
* Angular service mirroring the React `useGridData` hook and the Vue
|
|
467
|
+
* `useGridData` composable. Wraps `createMutableClientDataSource` with
|
|
468
|
+
* automatic cleanup on component destroy.
|
|
469
|
+
*
|
|
470
|
+
* Provided per-component via {@link provideGridData}; injected via
|
|
471
|
+
* {@link injectGridData} (or `inject(GridDataService)` with a manual cast).
|
|
472
|
+
*/
|
|
473
|
+
declare class GridDataService<TData = unknown> implements OnDestroy {
|
|
474
|
+
readonly dataSource: MutableDataSource<TData>;
|
|
475
|
+
constructor();
|
|
476
|
+
updateRow(id: RowId, data: Partial<TData>): void;
|
|
477
|
+
addRows(rows: TData[]): void;
|
|
478
|
+
removeRows(ids: RowId[]): void;
|
|
479
|
+
updateCell(id: RowId, field: string, value: CellValue): void;
|
|
480
|
+
clear(): void;
|
|
481
|
+
getRowById(id: RowId): TData | undefined;
|
|
482
|
+
getTotalRowCount(): number;
|
|
483
|
+
flushTransactions(): Promise<void>;
|
|
484
|
+
ngOnDestroy(): void;
|
|
485
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<GridDataService<any>, never>;
|
|
486
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<GridDataService<any>>;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Typed convenience helper for `inject(GridDataService) as GridDataService<TData>`.
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* ```ts
|
|
493
|
+
* @Component({
|
|
494
|
+
* providers: [provideGridData<Person>({ getRowId: (r) => r.id, initialData: rows })],
|
|
495
|
+
* })
|
|
496
|
+
* export class MyGridComponent {
|
|
497
|
+
* protected readonly grid = injectGridData<Person>();
|
|
498
|
+
* }
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
declare const injectGridData: <TData>() => GridDataService<TData>;
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Returns the providers needed to bind a {@link GridDataService} to the
|
|
505
|
+
* current injector (typically a component's `providers` array). The service
|
|
506
|
+
* is scoped to that injector — registering it on a parent injector would
|
|
507
|
+
* silently share the underlying data source between children.
|
|
508
|
+
*
|
|
509
|
+
* @example
|
|
510
|
+
* ```ts
|
|
511
|
+
* @Component({
|
|
512
|
+
* providers: [provideGridData<Person>({ getRowId: (r) => r.id, initialData: rows })],
|
|
513
|
+
* })
|
|
514
|
+
* export class MyGridComponent {
|
|
515
|
+
* protected readonly grid = injectGridData<Person>();
|
|
516
|
+
* }
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
declare const provideGridData: <TData>(options: GridDataOptions<TData>) => Provider[];
|
|
520
|
+
|
|
521
|
+
export { FilterPopupComponent, GRID_DATA_OPTIONS, GpGridComponent, GridBodyComponent, GridDataService, GridHeaderComponent, GridOverlaysComponent, createGridData, injectGridData, provideGridData };
|
|
522
|
+
export type { ActiveFilterPopup, AngularColumnDefinition, CellClassFn, CellDoubleClickEvent, CellPointerDownEvent, CellPointerEnterEvent, CellRendererTemplate, CreateGridDataOptions, EditRendererTemplate, EditingCellState, FillHandlePointerDownEvent, FilterPointerDownEvent, GridDataApi, GridDataOptions, HeaderPointerDownEvent, HeaderRendererTemplate, HeaderSortEvent, ResizePointerDownEvent, RowClassFn };
|