@toolbox-web/grid-angular 0.7.2 → 0.9.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
CHANGED
|
@@ -14,6 +14,7 @@ Angular adapter for `@toolbox-web/grid` data grid component. Provides directives
|
|
|
14
14
|
- ✅ **Template-driven editors** - Use `<ng-template>` for custom cell editors
|
|
15
15
|
- ✅ **Component-class column config** - Specify component classes directly in `gridConfig.columns`
|
|
16
16
|
- ✅ **Type-level defaults** - App-wide renderers/editors via `provideGridTypeDefaults()`
|
|
17
|
+
- ✅ **Icon configuration** - App-wide icon overrides via `provideGridIcons()`
|
|
17
18
|
- ✅ **Reactive Forms integration** - Use `formControlName` and `formControl` bindings
|
|
18
19
|
- ✅ **Auto-wiring** - Editor components just emit events, no manual binding needed
|
|
19
20
|
- ✅ **Full type safety** - Typed template contexts (`GridCellContext`, `GridEditorContext`)
|
|
@@ -359,6 +360,68 @@ export class MyGridComponent {
|
|
|
359
360
|
| `GridTypeRegistry` | Injectable service for dynamic registration |
|
|
360
361
|
| `GRID_TYPE_DEFAULTS` | Injection token for type defaults |
|
|
361
362
|
|
|
363
|
+
## App-Wide Icon Configuration
|
|
364
|
+
|
|
365
|
+
Customize grid icons at the application level using `provideGridIcons()`:
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
// app.config.ts
|
|
369
|
+
import { ApplicationConfig } from '@angular/core';
|
|
370
|
+
import { provideGridIcons } from '@toolbox-web/grid-angular';
|
|
371
|
+
|
|
372
|
+
export const appConfig: ApplicationConfig = {
|
|
373
|
+
providers: [
|
|
374
|
+
provideGridIcons({
|
|
375
|
+
expand: '➕',
|
|
376
|
+
collapse: '➖',
|
|
377
|
+
sortAsc: '↑',
|
|
378
|
+
sortDesc: '↓',
|
|
379
|
+
filter: '<svg viewBox="0 0 16 16">...</svg>',
|
|
380
|
+
}),
|
|
381
|
+
],
|
|
382
|
+
};
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Dynamic Icon Registration:**
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
import { Component, inject, OnInit } from '@angular/core';
|
|
389
|
+
import { GridIconRegistry } from '@toolbox-web/grid-angular';
|
|
390
|
+
|
|
391
|
+
@Component({ ... })
|
|
392
|
+
export class AppComponent implements OnInit {
|
|
393
|
+
private iconRegistry = inject(GridIconRegistry);
|
|
394
|
+
|
|
395
|
+
ngOnInit() {
|
|
396
|
+
// Dynamically set icons
|
|
397
|
+
this.iconRegistry.set('expand', '▶');
|
|
398
|
+
this.iconRegistry.set('collapse', '▼');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Available Icons:**
|
|
404
|
+
|
|
405
|
+
| Icon | Default | Description |
|
|
406
|
+
| -------------- | ------- | ------------------------------------ |
|
|
407
|
+
| `expand` | `▶` | Expand icon for trees/groups/details |
|
|
408
|
+
| `collapse` | `▼` | Collapse icon |
|
|
409
|
+
| `sortAsc` | `▲` | Sort ascending indicator |
|
|
410
|
+
| `sortDesc` | `▼` | Sort descending indicator |
|
|
411
|
+
| `sortNone` | `⇅` | Unsorted indicator |
|
|
412
|
+
| `filter` | SVG | Filter icon in headers |
|
|
413
|
+
| `filterActive` | SVG | Filter icon when active |
|
|
414
|
+
| `submenuArrow` | `▶` | Context menu submenu arrow |
|
|
415
|
+
| `dragHandle` | `⋮⋮` | Drag handle for reordering |
|
|
416
|
+
| `toolPanel` | `☰` | Tool panel toggle icon |
|
|
417
|
+
| `print` | `🖨️` | Print button icon |
|
|
418
|
+
|
|
419
|
+
**Precedence (highest wins):**
|
|
420
|
+
|
|
421
|
+
1. `gridConfig.icons` - Per-grid overrides
|
|
422
|
+
2. `provideGridIcons()` - App-level defaults
|
|
423
|
+
3. Built-in defaults
|
|
424
|
+
|
|
362
425
|
## Component-Class Column Config
|
|
363
426
|
|
|
364
427
|
For maximum flexibility and type safety, you can specify Angular component classes directly in your `gridConfig.columns`. This approach gives you full control over the component lifecycle while keeping your grid configuration clean and concise.
|
|
@@ -782,6 +845,14 @@ if (context?.hasFormGroups) {
|
|
|
782
845
|
| `GridTypeRegistry` | Injectable service for dynamic registration |
|
|
783
846
|
| `GRID_TYPE_DEFAULTS` | Injection token for type defaults |
|
|
784
847
|
|
|
848
|
+
### Icon Registry
|
|
849
|
+
|
|
850
|
+
| Export | Description |
|
|
851
|
+
| -------------------- | ------------------------------------------------ |
|
|
852
|
+
| `provideGridIcons()` | Provider factory for app-level icon overrides |
|
|
853
|
+
| `GridIconRegistry` | Injectable service for dynamic icon registration |
|
|
854
|
+
| `GRID_ICONS` | Injection token for icon overrides |
|
|
855
|
+
|
|
785
856
|
### Grid Directive Inputs
|
|
786
857
|
|
|
787
858
|
| Input | Type | Description |
|
|
@@ -341,11 +341,23 @@ function getFormArrayContext(gridElement) {
|
|
|
341
341
|
class GridFormArray {
|
|
342
342
|
elementRef = inject((ElementRef));
|
|
343
343
|
cellCommitListener = null;
|
|
344
|
+
rowCommitListener = null;
|
|
344
345
|
touchListener = null;
|
|
345
346
|
/**
|
|
346
347
|
* The FormArray to bind to the grid.
|
|
347
348
|
*/
|
|
348
349
|
formArray = input.required(...(ngDevMode ? [{ debugName: "formArray" }] : []));
|
|
350
|
+
/**
|
|
351
|
+
* Whether to automatically sync Angular validation state to grid's visual invalid styling.
|
|
352
|
+
*
|
|
353
|
+
* When enabled:
|
|
354
|
+
* - After a cell commit, if the FormControl is invalid, the cell is marked with `setInvalid()`
|
|
355
|
+
* - When a FormControl becomes valid, `clearInvalid()` is called
|
|
356
|
+
* - On `row-commit`, if the row's FormGroup has invalid controls, the commit is prevented
|
|
357
|
+
*
|
|
358
|
+
* @default true
|
|
359
|
+
*/
|
|
360
|
+
syncValidation = input(true, ...(ngDevMode ? [{ debugName: "syncValidation" }] : []));
|
|
349
361
|
/**
|
|
350
362
|
* Effect that syncs the FormArray value to the grid rows.
|
|
351
363
|
*/
|
|
@@ -369,6 +381,14 @@ class GridFormArray {
|
|
|
369
381
|
this.#handleCellCommit(detail);
|
|
370
382
|
};
|
|
371
383
|
grid.addEventListener('cell-commit', this.cellCommitListener);
|
|
384
|
+
// Intercept row-commit events to prevent if FormGroup is invalid
|
|
385
|
+
this.rowCommitListener = (e) => {
|
|
386
|
+
if (!this.syncValidation())
|
|
387
|
+
return;
|
|
388
|
+
const detail = e.detail;
|
|
389
|
+
this.#handleRowCommit(e, detail);
|
|
390
|
+
};
|
|
391
|
+
grid.addEventListener('row-commit', this.rowCommitListener);
|
|
372
392
|
// Mark FormArray as touched on first interaction
|
|
373
393
|
this.touchListener = () => {
|
|
374
394
|
this.formArray().markAsTouched();
|
|
@@ -387,6 +407,9 @@ class GridFormArray {
|
|
|
387
407
|
if (this.cellCommitListener) {
|
|
388
408
|
grid.removeEventListener('cell-commit', this.cellCommitListener);
|
|
389
409
|
}
|
|
410
|
+
if (this.rowCommitListener) {
|
|
411
|
+
grid.removeEventListener('row-commit', this.rowCommitListener);
|
|
412
|
+
}
|
|
390
413
|
if (this.touchListener) {
|
|
391
414
|
grid.removeEventListener('click', this.touchListener);
|
|
392
415
|
}
|
|
@@ -491,7 +514,7 @@ class GridFormArray {
|
|
|
491
514
|
* Handles cell-commit events by updating the FormControl in the FormGroup.
|
|
492
515
|
*/
|
|
493
516
|
#handleCellCommit(detail) {
|
|
494
|
-
const { rowIndex, field, value } = detail;
|
|
517
|
+
const { rowIndex, field, value, rowId } = detail;
|
|
495
518
|
const rowFormGroup = this.#getRowFormGroup(rowIndex);
|
|
496
519
|
if (rowFormGroup) {
|
|
497
520
|
const control = rowFormGroup.get(field);
|
|
@@ -499,18 +522,83 @@ class GridFormArray {
|
|
|
499
522
|
control.setValue(value);
|
|
500
523
|
control.markAsDirty();
|
|
501
524
|
control.markAsTouched();
|
|
525
|
+
// Sync Angular validation state to grid's visual invalid styling
|
|
526
|
+
if (this.syncValidation() && rowId) {
|
|
527
|
+
this.#syncControlValidationToGrid(rowId, field, control);
|
|
528
|
+
}
|
|
502
529
|
}
|
|
503
530
|
}
|
|
504
531
|
}
|
|
532
|
+
/**
|
|
533
|
+
* Handles row-commit events - prevents commit if FormGroup has invalid controls.
|
|
534
|
+
*/
|
|
535
|
+
#handleRowCommit(event, detail) {
|
|
536
|
+
const { rowIndex } = detail;
|
|
537
|
+
const rowFormGroup = this.#getRowFormGroup(rowIndex);
|
|
538
|
+
if (rowFormGroup && rowFormGroup.invalid) {
|
|
539
|
+
// Prevent row commit if the FormGroup is invalid
|
|
540
|
+
event.preventDefault();
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Syncs a FormControl's validation state to the grid's visual invalid styling.
|
|
545
|
+
*/
|
|
546
|
+
#syncControlValidationToGrid(rowId, field, control) {
|
|
547
|
+
const grid = this.elementRef.nativeElement;
|
|
548
|
+
if (!grid)
|
|
549
|
+
return;
|
|
550
|
+
// Get EditingPlugin via getPluginByName
|
|
551
|
+
const editingPlugin = grid.getPluginByName?.('editing');
|
|
552
|
+
if (!editingPlugin)
|
|
553
|
+
return;
|
|
554
|
+
if (control.invalid) {
|
|
555
|
+
// Get first error message to display
|
|
556
|
+
const errorMessage = this.#getFirstErrorMessage(control);
|
|
557
|
+
editingPlugin.setInvalid(rowId, field, errorMessage);
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
editingPlugin.clearInvalid(rowId, field);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Gets a human-readable error message from the first validation error.
|
|
565
|
+
*/
|
|
566
|
+
#getFirstErrorMessage(control) {
|
|
567
|
+
const errors = control.errors;
|
|
568
|
+
if (!errors)
|
|
569
|
+
return '';
|
|
570
|
+
const firstKey = Object.keys(errors)[0];
|
|
571
|
+
const error = errors[firstKey];
|
|
572
|
+
// Common Angular validators
|
|
573
|
+
switch (firstKey) {
|
|
574
|
+
case 'required':
|
|
575
|
+
return 'This field is required';
|
|
576
|
+
case 'minlength':
|
|
577
|
+
return `Minimum length is ${error.requiredLength}`;
|
|
578
|
+
case 'maxlength':
|
|
579
|
+
return `Maximum length is ${error.requiredLength}`;
|
|
580
|
+
case 'min':
|
|
581
|
+
return `Minimum value is ${error.min}`;
|
|
582
|
+
case 'max':
|
|
583
|
+
return `Maximum value is ${error.max}`;
|
|
584
|
+
case 'email':
|
|
585
|
+
return 'Invalid email address';
|
|
586
|
+
case 'pattern':
|
|
587
|
+
return 'Invalid format';
|
|
588
|
+
default:
|
|
589
|
+
// Custom validators may provide a message property
|
|
590
|
+
return typeof error === 'string' ? error : (error?.message ?? `Validation error: ${firstKey}`);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
505
593
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: GridFormArray, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
506
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: GridFormArray, isStandalone: true, selector: "tbw-grid[formArray]", inputs: { formArray: { classPropertyName: "formArray", publicName: "formArray", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
594
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: GridFormArray, isStandalone: true, selector: "tbw-grid[formArray]", inputs: { formArray: { classPropertyName: "formArray", publicName: "formArray", isSignal: true, isRequired: true, transformFunction: null }, syncValidation: { classPropertyName: "syncValidation", publicName: "syncValidation", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
507
595
|
}
|
|
508
596
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: GridFormArray, decorators: [{
|
|
509
597
|
type: Directive,
|
|
510
598
|
args: [{
|
|
511
599
|
selector: 'tbw-grid[formArray]',
|
|
512
600
|
}]
|
|
513
|
-
}], propDecorators: { formArray: [{ type: i0.Input, args: [{ isSignal: true, alias: "formArray", required: true }] }] } });
|
|
601
|
+
}], propDecorators: { formArray: [{ type: i0.Input, args: [{ isSignal: true, alias: "formArray", required: true }] }], syncValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "syncValidation", required: false }] }] } });
|
|
514
602
|
|
|
515
603
|
/**
|
|
516
604
|
* Registry to store responsive card templates by grid element.
|
|
@@ -1612,6 +1700,149 @@ class AngularGridAdapter {
|
|
|
1612
1700
|
}
|
|
1613
1701
|
}
|
|
1614
1702
|
|
|
1703
|
+
/**
|
|
1704
|
+
* Icon configuration registry for Angular applications.
|
|
1705
|
+
*
|
|
1706
|
+
* Provides application-wide icon overrides for all grids via
|
|
1707
|
+
* Angular's dependency injection.
|
|
1708
|
+
*/
|
|
1709
|
+
/**
|
|
1710
|
+
* Injection token for providing icon overrides at app level.
|
|
1711
|
+
*/
|
|
1712
|
+
const GRID_ICONS = new InjectionToken('GRID_ICONS');
|
|
1713
|
+
/**
|
|
1714
|
+
* Injectable service for managing grid icons.
|
|
1715
|
+
*
|
|
1716
|
+
* Use `provideGridIcons()` in your app config to set up icons,
|
|
1717
|
+
* or inject this service for dynamic registration.
|
|
1718
|
+
*
|
|
1719
|
+
* @example
|
|
1720
|
+
* ```typescript
|
|
1721
|
+
* // App-level setup (app.config.ts)
|
|
1722
|
+
* export const appConfig: ApplicationConfig = {
|
|
1723
|
+
* providers: [
|
|
1724
|
+
* provideGridIcons({
|
|
1725
|
+
* expand: '➕',
|
|
1726
|
+
* collapse: '➖',
|
|
1727
|
+
* sortAsc: '↑',
|
|
1728
|
+
* sortDesc: '↓',
|
|
1729
|
+
* })
|
|
1730
|
+
* ]
|
|
1731
|
+
* };
|
|
1732
|
+
*
|
|
1733
|
+
* // Dynamic registration
|
|
1734
|
+
* @Component({ ... })
|
|
1735
|
+
* export class AppComponent {
|
|
1736
|
+
* private registry = inject(GridIconRegistry);
|
|
1737
|
+
*
|
|
1738
|
+
* ngOnInit() {
|
|
1739
|
+
* this.registry.set('filter', '<svg>...</svg>');
|
|
1740
|
+
* }
|
|
1741
|
+
* }
|
|
1742
|
+
* ```
|
|
1743
|
+
*/
|
|
1744
|
+
class GridIconRegistry {
|
|
1745
|
+
icons = new Map();
|
|
1746
|
+
constructor() {
|
|
1747
|
+
// Merge any initial icons from provider
|
|
1748
|
+
const initial = inject(GRID_ICONS, { optional: true });
|
|
1749
|
+
if (initial) {
|
|
1750
|
+
for (const [key, value] of Object.entries(initial)) {
|
|
1751
|
+
this.icons.set(key, value);
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Set an icon override.
|
|
1757
|
+
*
|
|
1758
|
+
* @param name - The icon name (e.g., 'expand', 'collapse', 'filter')
|
|
1759
|
+
* @param value - The icon value (string text or SVG markup)
|
|
1760
|
+
*/
|
|
1761
|
+
set(name, value) {
|
|
1762
|
+
this.icons.set(name, value);
|
|
1763
|
+
}
|
|
1764
|
+
/**
|
|
1765
|
+
* Get an icon value.
|
|
1766
|
+
*/
|
|
1767
|
+
get(name) {
|
|
1768
|
+
return this.icons.get(name);
|
|
1769
|
+
}
|
|
1770
|
+
/**
|
|
1771
|
+
* Remove an icon override.
|
|
1772
|
+
*/
|
|
1773
|
+
remove(name) {
|
|
1774
|
+
this.icons.delete(name);
|
|
1775
|
+
}
|
|
1776
|
+
/**
|
|
1777
|
+
* Check if an icon has an override.
|
|
1778
|
+
*/
|
|
1779
|
+
has(name) {
|
|
1780
|
+
return this.icons.has(name);
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* Get all icon overrides as a GridIcons partial.
|
|
1784
|
+
* Used internally by the adapter.
|
|
1785
|
+
*
|
|
1786
|
+
* @internal
|
|
1787
|
+
*/
|
|
1788
|
+
getAll() {
|
|
1789
|
+
const result = {};
|
|
1790
|
+
for (const [key, value] of this.icons) {
|
|
1791
|
+
result[key] = value;
|
|
1792
|
+
}
|
|
1793
|
+
return result;
|
|
1794
|
+
}
|
|
1795
|
+
/**
|
|
1796
|
+
* Get all registered icon names.
|
|
1797
|
+
*/
|
|
1798
|
+
getRegisteredIcons() {
|
|
1799
|
+
return Array.from(this.icons.keys());
|
|
1800
|
+
}
|
|
1801
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: GridIconRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1802
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: GridIconRegistry, providedIn: 'root' });
|
|
1803
|
+
}
|
|
1804
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: GridIconRegistry, decorators: [{
|
|
1805
|
+
type: Injectable,
|
|
1806
|
+
args: [{ providedIn: 'root' }]
|
|
1807
|
+
}], ctorParameters: () => [] });
|
|
1808
|
+
/**
|
|
1809
|
+
* Provides application-level icon overrides for all grids.
|
|
1810
|
+
*
|
|
1811
|
+
* Available icons to override:
|
|
1812
|
+
* - `expand` - Expand icon for collapsed items (trees, groups, details)
|
|
1813
|
+
* - `collapse` - Collapse icon for expanded items
|
|
1814
|
+
* - `sortAsc` - Sort ascending indicator
|
|
1815
|
+
* - `sortDesc` - Sort descending indicator
|
|
1816
|
+
* - `sortNone` - Sort neutral/unsorted indicator
|
|
1817
|
+
* - `submenuArrow` - Submenu arrow for context menus
|
|
1818
|
+
* - `dragHandle` - Drag handle icon for reordering
|
|
1819
|
+
* - `toolPanel` - Tool panel toggle icon in toolbar
|
|
1820
|
+
* - `filter` - Filter icon in column headers
|
|
1821
|
+
* - `filterActive` - Filter icon when filter is active
|
|
1822
|
+
* - `print` - Print icon for print button
|
|
1823
|
+
*
|
|
1824
|
+
* @example
|
|
1825
|
+
* ```typescript
|
|
1826
|
+
* // app.config.ts
|
|
1827
|
+
* import { provideGridIcons } from '@toolbox-web/grid-angular';
|
|
1828
|
+
*
|
|
1829
|
+
* export const appConfig: ApplicationConfig = {
|
|
1830
|
+
* providers: [
|
|
1831
|
+
* provideGridIcons({
|
|
1832
|
+
* expand: '➕',
|
|
1833
|
+
* collapse: '➖',
|
|
1834
|
+
* sortAsc: '↑',
|
|
1835
|
+
* sortDesc: '↓',
|
|
1836
|
+
* filter: '<svg viewBox="0 0 16 16">...</svg>',
|
|
1837
|
+
* })
|
|
1838
|
+
* ]
|
|
1839
|
+
* };
|
|
1840
|
+
* ```
|
|
1841
|
+
*/
|
|
1842
|
+
function provideGridIcons(icons) {
|
|
1843
|
+
return makeEnvironmentProviders([{ provide: GRID_ICONS, useValue: icons }]);
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1615
1846
|
/**
|
|
1616
1847
|
* Angular inject function for programmatic access to a grid instance.
|
|
1617
1848
|
*
|
|
@@ -2186,6 +2417,7 @@ class Grid {
|
|
|
2186
2417
|
injector = inject(EnvironmentInjector);
|
|
2187
2418
|
appRef = inject(ApplicationRef);
|
|
2188
2419
|
viewContainerRef = inject(ViewContainerRef);
|
|
2420
|
+
iconRegistry = inject(GridIconRegistry, { optional: true });
|
|
2189
2421
|
adapter = null;
|
|
2190
2422
|
constructor() {
|
|
2191
2423
|
// Effect to process angularConfig and apply to grid
|
|
@@ -2215,6 +2447,13 @@ class Grid {
|
|
|
2215
2447
|
if (selectableValue !== undefined) {
|
|
2216
2448
|
coreConfigOverrides['selectable'] = selectableValue;
|
|
2217
2449
|
}
|
|
2450
|
+
// Merge icon overrides from registry with any existing icons in config
|
|
2451
|
+
// Registry icons are base, config.icons override them
|
|
2452
|
+
const registryIcons = this.iconRegistry?.getAll();
|
|
2453
|
+
if (registryIcons && Object.keys(registryIcons).length > 0) {
|
|
2454
|
+
const existingIcons = processedConfig?.icons || config?.icons || {};
|
|
2455
|
+
coreConfigOverrides['icons'] = { ...registryIcons, ...existingIcons };
|
|
2456
|
+
}
|
|
2218
2457
|
// Apply to the grid element
|
|
2219
2458
|
const grid = this.elementRef.nativeElement;
|
|
2220
2459
|
grid.gridConfig = {
|
|
@@ -2223,6 +2462,14 @@ class Grid {
|
|
|
2223
2462
|
plugins: mergedPlugins.length > 0 ? mergedPlugins : undefined,
|
|
2224
2463
|
};
|
|
2225
2464
|
});
|
|
2465
|
+
// Effect to sync loading state to the grid element
|
|
2466
|
+
effect(() => {
|
|
2467
|
+
const loadingValue = this.loading();
|
|
2468
|
+
if (loadingValue === undefined)
|
|
2469
|
+
return;
|
|
2470
|
+
const grid = this.elementRef.nativeElement;
|
|
2471
|
+
grid.loading = loadingValue;
|
|
2472
|
+
});
|
|
2226
2473
|
}
|
|
2227
2474
|
/**
|
|
2228
2475
|
* Custom CSS styles to inject into the grid.
|
|
@@ -2303,6 +2550,34 @@ class Grid {
|
|
|
2303
2550
|
* ```
|
|
2304
2551
|
*/
|
|
2305
2552
|
selectable = input(...(ngDevMode ? [undefined, { debugName: "selectable" }] : []));
|
|
2553
|
+
/**
|
|
2554
|
+
* Show a loading overlay on the grid.
|
|
2555
|
+
* Use this during initial data fetch or refresh operations.
|
|
2556
|
+
*
|
|
2557
|
+
* For row/cell loading states, access the grid element directly:
|
|
2558
|
+
* - `grid.setRowLoading(rowId, true/false)`
|
|
2559
|
+
* - `grid.setCellLoading(rowId, field, true/false)`
|
|
2560
|
+
*
|
|
2561
|
+
* @default false
|
|
2562
|
+
*
|
|
2563
|
+
* @example
|
|
2564
|
+
* ```html
|
|
2565
|
+
* <!-- Show loading during data fetch -->
|
|
2566
|
+
* <tbw-grid [loading]="isLoading" [rows]="rows" />
|
|
2567
|
+
* ```
|
|
2568
|
+
*
|
|
2569
|
+
* ```typescript
|
|
2570
|
+
* isLoading = true;
|
|
2571
|
+
*
|
|
2572
|
+
* ngOnInit() {
|
|
2573
|
+
* this.dataService.fetchData().subscribe(data => {
|
|
2574
|
+
* this.rows = data;
|
|
2575
|
+
* this.isLoading = false;
|
|
2576
|
+
* });
|
|
2577
|
+
* }
|
|
2578
|
+
* ```
|
|
2579
|
+
*/
|
|
2580
|
+
loading = input(...(ngDevMode ? [undefined, { debugName: "loading" }] : []));
|
|
2306
2581
|
/**
|
|
2307
2582
|
* Angular-specific grid configuration that supports component classes for renderers/editors.
|
|
2308
2583
|
*
|
|
@@ -3167,12 +3442,12 @@ class Grid {
|
|
|
3167
3442
|
}
|
|
3168
3443
|
}
|
|
3169
3444
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: Grid, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3170
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: Grid, isStandalone: true, selector: "tbw-grid", inputs: { customStyles: { classPropertyName: "customStyles", publicName: "customStyles", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, angularConfig: { classPropertyName: "angularConfig", publicName: "angularConfig", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, editing: { classPropertyName: "editing", publicName: "editing", isSignal: true, isRequired: false, transformFunction: null }, clipboard: { classPropertyName: "clipboard", publicName: "clipboard", isSignal: true, isRequired: false, transformFunction: null }, contextMenu: { classPropertyName: "contextMenu", publicName: "contextMenu", isSignal: true, isRequired: false, transformFunction: null }, multiSort: { classPropertyName: "multiSort", publicName: "multiSort", isSignal: true, isRequired: false, transformFunction: null }, sorting: { classPropertyName: "sorting", publicName: "sorting", isSignal: true, isRequired: false, transformFunction: null }, filtering: { classPropertyName: "filtering", publicName: "filtering", isSignal: true, isRequired: false, transformFunction: null }, reorder: { classPropertyName: "reorder", publicName: "reorder", isSignal: true, isRequired: false, transformFunction: null }, visibility: { classPropertyName: "visibility", publicName: "visibility", isSignal: true, isRequired: false, transformFunction: null }, pinnedColumns: { classPropertyName: "pinnedColumns", publicName: "pinnedColumns", isSignal: true, isRequired: false, transformFunction: null }, groupingColumns: { classPropertyName: "groupingColumns", publicName: "groupingColumns", isSignal: true, isRequired: false, transformFunction: null }, columnVirtualization: { classPropertyName: "columnVirtualization", publicName: "columnVirtualization", isSignal: true, isRequired: false, transformFunction: null }, rowReorder: { classPropertyName: "rowReorder", publicName: "rowReorder", isSignal: true, isRequired: false, transformFunction: null }, groupingRows: { classPropertyName: "groupingRows", publicName: "groupingRows", isSignal: true, isRequired: false, transformFunction: null }, pinnedRows: { classPropertyName: "pinnedRows", publicName: "pinnedRows", isSignal: true, isRequired: false, transformFunction: null }, tree: { classPropertyName: "tree", publicName: "tree", isSignal: true, isRequired: false, transformFunction: null }, masterDetail: { classPropertyName: "masterDetail", publicName: "masterDetail", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, undoRedo: { classPropertyName: "undoRedo", publicName: "undoRedo", isSignal: true, isRequired: false, transformFunction: null }, exportFeature: { classPropertyName: "exportFeature", publicName: "exportFeature", isSignal: true, isRequired: false, transformFunction: null }, print: { classPropertyName: "print", publicName: "print", isSignal: true, isRequired: false, transformFunction: null }, pivot: { classPropertyName: "pivot", publicName: "pivot", isSignal: true, isRequired: false, transformFunction: null }, serverSide: { classPropertyName: "serverSide", publicName: "serverSide", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellClick: "cellClick", rowClick: "rowClick", cellActivate: "cellActivate", cellChange: "cellChange", cellCommit: "cellCommit", rowCommit: "rowCommit", changedRowsReset: "changedRowsReset", sortChange: "sortChange", filterChange: "filterChange", columnResize: "columnResize", columnMove: "columnMove", columnVisibility: "columnVisibility", columnStateChange: "columnStateChange", selectionChange: "selectionChange", rowMove: "rowMove", groupToggle: "groupToggle", treeExpand: "treeExpand", detailExpand: "detailExpand", responsiveChange: "responsiveChange", copy: "copy", paste: "paste", undoRedoAction: "undoRedoAction", exportComplete: "exportComplete", printStart: "printStart", printComplete: "printComplete" }, ngImport: i0 });
|
|
3445
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: Grid, isStandalone: true, selector: "tbw-grid", inputs: { customStyles: { classPropertyName: "customStyles", publicName: "customStyles", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, angularConfig: { classPropertyName: "angularConfig", publicName: "angularConfig", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, editing: { classPropertyName: "editing", publicName: "editing", isSignal: true, isRequired: false, transformFunction: null }, clipboard: { classPropertyName: "clipboard", publicName: "clipboard", isSignal: true, isRequired: false, transformFunction: null }, contextMenu: { classPropertyName: "contextMenu", publicName: "contextMenu", isSignal: true, isRequired: false, transformFunction: null }, multiSort: { classPropertyName: "multiSort", publicName: "multiSort", isSignal: true, isRequired: false, transformFunction: null }, sorting: { classPropertyName: "sorting", publicName: "sorting", isSignal: true, isRequired: false, transformFunction: null }, filtering: { classPropertyName: "filtering", publicName: "filtering", isSignal: true, isRequired: false, transformFunction: null }, reorder: { classPropertyName: "reorder", publicName: "reorder", isSignal: true, isRequired: false, transformFunction: null }, visibility: { classPropertyName: "visibility", publicName: "visibility", isSignal: true, isRequired: false, transformFunction: null }, pinnedColumns: { classPropertyName: "pinnedColumns", publicName: "pinnedColumns", isSignal: true, isRequired: false, transformFunction: null }, groupingColumns: { classPropertyName: "groupingColumns", publicName: "groupingColumns", isSignal: true, isRequired: false, transformFunction: null }, columnVirtualization: { classPropertyName: "columnVirtualization", publicName: "columnVirtualization", isSignal: true, isRequired: false, transformFunction: null }, rowReorder: { classPropertyName: "rowReorder", publicName: "rowReorder", isSignal: true, isRequired: false, transformFunction: null }, groupingRows: { classPropertyName: "groupingRows", publicName: "groupingRows", isSignal: true, isRequired: false, transformFunction: null }, pinnedRows: { classPropertyName: "pinnedRows", publicName: "pinnedRows", isSignal: true, isRequired: false, transformFunction: null }, tree: { classPropertyName: "tree", publicName: "tree", isSignal: true, isRequired: false, transformFunction: null }, masterDetail: { classPropertyName: "masterDetail", publicName: "masterDetail", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, undoRedo: { classPropertyName: "undoRedo", publicName: "undoRedo", isSignal: true, isRequired: false, transformFunction: null }, exportFeature: { classPropertyName: "exportFeature", publicName: "exportFeature", isSignal: true, isRequired: false, transformFunction: null }, print: { classPropertyName: "print", publicName: "print", isSignal: true, isRequired: false, transformFunction: null }, pivot: { classPropertyName: "pivot", publicName: "pivot", isSignal: true, isRequired: false, transformFunction: null }, serverSide: { classPropertyName: "serverSide", publicName: "serverSide", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellClick: "cellClick", rowClick: "rowClick", cellActivate: "cellActivate", cellChange: "cellChange", cellCommit: "cellCommit", rowCommit: "rowCommit", changedRowsReset: "changedRowsReset", sortChange: "sortChange", filterChange: "filterChange", columnResize: "columnResize", columnMove: "columnMove", columnVisibility: "columnVisibility", columnStateChange: "columnStateChange", selectionChange: "selectionChange", rowMove: "rowMove", groupToggle: "groupToggle", treeExpand: "treeExpand", detailExpand: "detailExpand", responsiveChange: "responsiveChange", copy: "copy", paste: "paste", undoRedoAction: "undoRedoAction", exportComplete: "exportComplete", printStart: "printStart", printComplete: "printComplete" }, ngImport: i0 });
|
|
3171
3446
|
}
|
|
3172
3447
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: Grid, decorators: [{
|
|
3173
3448
|
type: Directive,
|
|
3174
3449
|
args: [{ selector: 'tbw-grid' }]
|
|
3175
|
-
}], ctorParameters: () => [], propDecorators: { customStyles: [{ type: i0.Input, args: [{ isSignal: true, alias: "customStyles", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], angularConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "angularConfig", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }], editing: [{ type: i0.Input, args: [{ isSignal: true, alias: "editing", required: false }] }], clipboard: [{ type: i0.Input, args: [{ isSignal: true, alias: "clipboard", required: false }] }], contextMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextMenu", required: false }] }], multiSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiSort", required: false }] }], sorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "sorting", required: false }] }], filtering: [{ type: i0.Input, args: [{ isSignal: true, alias: "filtering", required: false }] }], reorder: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorder", required: false }] }], visibility: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibility", required: false }] }], pinnedColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinnedColumns", required: false }] }], groupingColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupingColumns", required: false }] }], columnVirtualization: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnVirtualization", required: false }] }], rowReorder: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowReorder", required: false }] }], groupingRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupingRows", required: false }] }], pinnedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinnedRows", required: false }] }], tree: [{ type: i0.Input, args: [{ isSignal: true, alias: "tree", required: false }] }], masterDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "masterDetail", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], undoRedo: [{ type: i0.Input, args: [{ isSignal: true, alias: "undoRedo", required: false }] }], exportFeature: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportFeature", required: false }] }], print: [{ type: i0.Input, args: [{ isSignal: true, alias: "print", required: false }] }], pivot: [{ type: i0.Input, args: [{ isSignal: true, alias: "pivot", required: false }] }], serverSide: [{ type: i0.Input, args: [{ isSignal: true, alias: "serverSide", required: false }] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], cellActivate: [{ type: i0.Output, args: ["cellActivate"] }], cellChange: [{ type: i0.Output, args: ["cellChange"] }], cellCommit: [{ type: i0.Output, args: ["cellCommit"] }], rowCommit: [{ type: i0.Output, args: ["rowCommit"] }], changedRowsReset: [{ type: i0.Output, args: ["changedRowsReset"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], columnResize: [{ type: i0.Output, args: ["columnResize"] }], columnMove: [{ type: i0.Output, args: ["columnMove"] }], columnVisibility: [{ type: i0.Output, args: ["columnVisibility"] }], columnStateChange: [{ type: i0.Output, args: ["columnStateChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], rowMove: [{ type: i0.Output, args: ["rowMove"] }], groupToggle: [{ type: i0.Output, args: ["groupToggle"] }], treeExpand: [{ type: i0.Output, args: ["treeExpand"] }], detailExpand: [{ type: i0.Output, args: ["detailExpand"] }], responsiveChange: [{ type: i0.Output, args: ["responsiveChange"] }], copy: [{ type: i0.Output, args: ["copy"] }], paste: [{ type: i0.Output, args: ["paste"] }], undoRedoAction: [{ type: i0.Output, args: ["undoRedoAction"] }], exportComplete: [{ type: i0.Output, args: ["exportComplete"] }], printStart: [{ type: i0.Output, args: ["printStart"] }], printComplete: [{ type: i0.Output, args: ["printComplete"] }] } });
|
|
3450
|
+
}], ctorParameters: () => [], propDecorators: { customStyles: [{ type: i0.Input, args: [{ isSignal: true, alias: "customStyles", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], angularConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "angularConfig", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }], editing: [{ type: i0.Input, args: [{ isSignal: true, alias: "editing", required: false }] }], clipboard: [{ type: i0.Input, args: [{ isSignal: true, alias: "clipboard", required: false }] }], contextMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextMenu", required: false }] }], multiSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiSort", required: false }] }], sorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "sorting", required: false }] }], filtering: [{ type: i0.Input, args: [{ isSignal: true, alias: "filtering", required: false }] }], reorder: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorder", required: false }] }], visibility: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibility", required: false }] }], pinnedColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinnedColumns", required: false }] }], groupingColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupingColumns", required: false }] }], columnVirtualization: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnVirtualization", required: false }] }], rowReorder: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowReorder", required: false }] }], groupingRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupingRows", required: false }] }], pinnedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinnedRows", required: false }] }], tree: [{ type: i0.Input, args: [{ isSignal: true, alias: "tree", required: false }] }], masterDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "masterDetail", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], undoRedo: [{ type: i0.Input, args: [{ isSignal: true, alias: "undoRedo", required: false }] }], exportFeature: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportFeature", required: false }] }], print: [{ type: i0.Input, args: [{ isSignal: true, alias: "print", required: false }] }], pivot: [{ type: i0.Input, args: [{ isSignal: true, alias: "pivot", required: false }] }], serverSide: [{ type: i0.Input, args: [{ isSignal: true, alias: "serverSide", required: false }] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], cellActivate: [{ type: i0.Output, args: ["cellActivate"] }], cellChange: [{ type: i0.Output, args: ["cellChange"] }], cellCommit: [{ type: i0.Output, args: ["cellCommit"] }], rowCommit: [{ type: i0.Output, args: ["rowCommit"] }], changedRowsReset: [{ type: i0.Output, args: ["changedRowsReset"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], columnResize: [{ type: i0.Output, args: ["columnResize"] }], columnMove: [{ type: i0.Output, args: ["columnMove"] }], columnVisibility: [{ type: i0.Output, args: ["columnVisibility"] }], columnStateChange: [{ type: i0.Output, args: ["columnStateChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], rowMove: [{ type: i0.Output, args: ["rowMove"] }], groupToggle: [{ type: i0.Output, args: ["groupToggle"] }], treeExpand: [{ type: i0.Output, args: ["treeExpand"] }], detailExpand: [{ type: i0.Output, args: ["detailExpand"] }], responsiveChange: [{ type: i0.Output, args: ["responsiveChange"] }], copy: [{ type: i0.Output, args: ["copy"] }], paste: [{ type: i0.Output, args: ["paste"] }], undoRedoAction: [{ type: i0.Output, args: ["undoRedoAction"] }], exportComplete: [{ type: i0.Output, args: ["exportComplete"] }], printStart: [{ type: i0.Output, args: ["printStart"] }], printComplete: [{ type: i0.Output, args: ["printComplete"] }] } });
|
|
3176
3451
|
|
|
3177
3452
|
/**
|
|
3178
3453
|
* @packageDocumentation
|
|
@@ -3185,5 +3460,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
|
|
|
3185
3460
|
* Generated bundle index. Do not edit.
|
|
3186
3461
|
*/
|
|
3187
3462
|
|
|
3188
|
-
export { AngularGridAdapter, BaseGridEditor, GRID_TYPE_DEFAULTS, Grid, GridColumnEditor, GridColumnView, GridDetailView, GridFormArray, GridResponsiveCard, GridToolPanel, GridTypeRegistry, TbwEditor as TbwCellEditor, TbwRenderer as TbwCellView, TbwEditor, TbwRenderer, clearFeatureRegistry, createPluginFromFeature, getFeatureFactory, getFormArrayContext, getRegisteredFeatures, injectGrid, isComponentClass, isFeatureRegistered, provideGridTypeDefaults, registerFeature };
|
|
3463
|
+
export { AngularGridAdapter, BaseGridEditor, GRID_ICONS, GRID_TYPE_DEFAULTS, Grid, GridColumnEditor, GridColumnView, GridDetailView, GridFormArray, GridIconRegistry, GridResponsiveCard, GridToolPanel, GridTypeRegistry, TbwEditor as TbwCellEditor, TbwRenderer as TbwCellView, TbwEditor, TbwRenderer, clearFeatureRegistry, createPluginFromFeature, getFeatureFactory, getFormArrayContext, getRegisteredFeatures, injectGrid, isComponentClass, isFeatureRegistered, provideGridIcons, provideGridTypeDefaults, registerFeature };
|
|
3189
3464
|
//# sourceMappingURL=toolbox-web-grid-angular.mjs.map
|