@toolbox-web/grid-angular 0.17.0 → 0.18.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.
|
@@ -1575,6 +1575,10 @@ class GridAdapter {
|
|
|
1575
1575
|
if (config.typeDefaults) {
|
|
1576
1576
|
result.typeDefaults = this.processTypeDefaults(config.typeDefaults);
|
|
1577
1577
|
}
|
|
1578
|
+
// Process loadingRenderer - convert Angular component class to function
|
|
1579
|
+
if (config.loadingRenderer && isComponentClass(config.loadingRenderer)) {
|
|
1580
|
+
result.loadingRenderer = this.createComponentLoadingRenderer(config.loadingRenderer);
|
|
1581
|
+
}
|
|
1578
1582
|
return result;
|
|
1579
1583
|
}
|
|
1580
1584
|
/**
|
|
@@ -1621,6 +1625,14 @@ class GridAdapter {
|
|
|
1621
1625
|
if (column.editor && isComponentClass(column.editor)) {
|
|
1622
1626
|
processed.editor = this.createComponentEditor(column.editor);
|
|
1623
1627
|
}
|
|
1628
|
+
// Convert headerRenderer component class to function
|
|
1629
|
+
if (column.headerRenderer && isComponentClass(column.headerRenderer)) {
|
|
1630
|
+
processed.headerRenderer = this.createComponentHeaderRenderer(column.headerRenderer);
|
|
1631
|
+
}
|
|
1632
|
+
// Convert headerLabelRenderer component class to function
|
|
1633
|
+
if (column.headerLabelRenderer && isComponentClass(column.headerLabelRenderer)) {
|
|
1634
|
+
processed.headerLabelRenderer = this.createComponentHeaderLabelRenderer(column.headerLabelRenderer);
|
|
1635
|
+
}
|
|
1624
1636
|
return processed;
|
|
1625
1637
|
}
|
|
1626
1638
|
/**
|
|
@@ -2094,6 +2106,222 @@ class GridAdapter {
|
|
|
2094
2106
|
return hostElement;
|
|
2095
2107
|
};
|
|
2096
2108
|
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Creates a header renderer function from an Angular component class.
|
|
2111
|
+
* Mounts the component with full header context (column, value, sortState, etc.).
|
|
2112
|
+
* @internal
|
|
2113
|
+
*/
|
|
2114
|
+
createComponentHeaderRenderer(componentClass) {
|
|
2115
|
+
return (ctx) => {
|
|
2116
|
+
const hostElement = document.createElement('span');
|
|
2117
|
+
hostElement.style.display = 'contents';
|
|
2118
|
+
const componentRef = createComponent(componentClass, {
|
|
2119
|
+
environmentInjector: this.injector,
|
|
2120
|
+
hostElement,
|
|
2121
|
+
});
|
|
2122
|
+
this.setComponentInputs(componentRef, {
|
|
2123
|
+
column: ctx.column,
|
|
2124
|
+
value: ctx.value,
|
|
2125
|
+
sortState: ctx.sortState,
|
|
2126
|
+
filterActive: ctx.filterActive,
|
|
2127
|
+
renderSortIcon: ctx.renderSortIcon,
|
|
2128
|
+
renderFilterButton: ctx.renderFilterButton,
|
|
2129
|
+
});
|
|
2130
|
+
this.appRef.attachView(componentRef.hostView);
|
|
2131
|
+
this.componentRefs.push(componentRef);
|
|
2132
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
2133
|
+
return hostElement;
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* Creates a header label renderer function from an Angular component class.
|
|
2138
|
+
* Mounts the component with label context (column, value).
|
|
2139
|
+
* @internal
|
|
2140
|
+
*/
|
|
2141
|
+
createComponentHeaderLabelRenderer(componentClass) {
|
|
2142
|
+
return (ctx) => {
|
|
2143
|
+
const hostElement = document.createElement('span');
|
|
2144
|
+
hostElement.style.display = 'contents';
|
|
2145
|
+
const componentRef = createComponent(componentClass, {
|
|
2146
|
+
environmentInjector: this.injector,
|
|
2147
|
+
hostElement,
|
|
2148
|
+
});
|
|
2149
|
+
this.setComponentInputs(componentRef, {
|
|
2150
|
+
column: ctx.column,
|
|
2151
|
+
value: ctx.value,
|
|
2152
|
+
});
|
|
2153
|
+
this.appRef.attachView(componentRef.hostView);
|
|
2154
|
+
this.componentRefs.push(componentRef);
|
|
2155
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
2156
|
+
return hostElement;
|
|
2157
|
+
};
|
|
2158
|
+
}
|
|
2159
|
+
/**
|
|
2160
|
+
* Creates a group header renderer function from an Angular component class.
|
|
2161
|
+
*
|
|
2162
|
+
* The component should accept group header inputs (id, label, columns, firstIndex, isImplicit).
|
|
2163
|
+
* Returns the host element directly (groupHeaderRenderer returns an element, not void).
|
|
2164
|
+
* @internal
|
|
2165
|
+
*/
|
|
2166
|
+
createComponentGroupHeaderRenderer(componentClass) {
|
|
2167
|
+
return (params) => {
|
|
2168
|
+
const hostElement = document.createElement('span');
|
|
2169
|
+
hostElement.style.display = 'contents';
|
|
2170
|
+
const componentRef = createComponent(componentClass, {
|
|
2171
|
+
environmentInjector: this.injector,
|
|
2172
|
+
hostElement,
|
|
2173
|
+
});
|
|
2174
|
+
this.setComponentInputs(componentRef, {
|
|
2175
|
+
id: params.id,
|
|
2176
|
+
label: params.label,
|
|
2177
|
+
columns: params.columns,
|
|
2178
|
+
firstIndex: params.firstIndex,
|
|
2179
|
+
isImplicit: params.isImplicit,
|
|
2180
|
+
});
|
|
2181
|
+
this.appRef.attachView(componentRef.hostView);
|
|
2182
|
+
this.componentRefs.push(componentRef);
|
|
2183
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
2184
|
+
return hostElement;
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
/**
|
|
2188
|
+
* Processes a GroupingColumnsConfig, converting component class references
|
|
2189
|
+
* to actual renderer functions.
|
|
2190
|
+
*
|
|
2191
|
+
* @param config - Angular grouping columns configuration with possible component class references
|
|
2192
|
+
* @returns Processed GroupingColumnsConfig with actual renderer functions
|
|
2193
|
+
*/
|
|
2194
|
+
processGroupingColumnsConfig(config) {
|
|
2195
|
+
if (config.groupHeaderRenderer && isComponentClass(config.groupHeaderRenderer)) {
|
|
2196
|
+
return {
|
|
2197
|
+
...config,
|
|
2198
|
+
groupHeaderRenderer: this.createComponentGroupHeaderRenderer(config.groupHeaderRenderer),
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
return config;
|
|
2202
|
+
}
|
|
2203
|
+
/**
|
|
2204
|
+
* Processes a GroupingRowsConfig, converting component class references
|
|
2205
|
+
* to actual renderer functions.
|
|
2206
|
+
*
|
|
2207
|
+
* @param config - Angular grouping rows configuration with possible component class references
|
|
2208
|
+
* @returns Processed GroupingRowsConfig with actual renderer functions
|
|
2209
|
+
*/
|
|
2210
|
+
processGroupingRowsConfig(config) {
|
|
2211
|
+
if (config.groupRowRenderer && isComponentClass(config.groupRowRenderer)) {
|
|
2212
|
+
return {
|
|
2213
|
+
...config,
|
|
2214
|
+
groupRowRenderer: this.createComponentGroupRowRenderer(config.groupRowRenderer),
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
return config;
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Processes a PinnedRowsConfig, converting component class references
|
|
2221
|
+
* in `customPanels[].render` to actual renderer functions.
|
|
2222
|
+
*
|
|
2223
|
+
* @param config - Angular pinned rows configuration with possible component class references
|
|
2224
|
+
* @returns Processed PinnedRowsConfig with actual renderer functions
|
|
2225
|
+
*/
|
|
2226
|
+
processPinnedRowsConfig(config) {
|
|
2227
|
+
if (!Array.isArray(config.customPanels))
|
|
2228
|
+
return config;
|
|
2229
|
+
const hasComponentRender = config.customPanels.some((panel) => isComponentClass(panel.render));
|
|
2230
|
+
if (!hasComponentRender)
|
|
2231
|
+
return config;
|
|
2232
|
+
return {
|
|
2233
|
+
...config,
|
|
2234
|
+
customPanels: config.customPanels.map((panel) => {
|
|
2235
|
+
if (!isComponentClass(panel.render))
|
|
2236
|
+
return panel;
|
|
2237
|
+
return {
|
|
2238
|
+
...panel,
|
|
2239
|
+
render: this.createComponentPinnedRowsPanelRenderer(panel.render),
|
|
2240
|
+
};
|
|
2241
|
+
}),
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Creates a pinned rows panel renderer function from an Angular component class.
|
|
2246
|
+
*
|
|
2247
|
+
* The component should accept inputs from PinnedRowsContext (totalRows, filteredRows,
|
|
2248
|
+
* selectedRows, columns, rows, grid).
|
|
2249
|
+
* @internal
|
|
2250
|
+
*/
|
|
2251
|
+
createComponentPinnedRowsPanelRenderer(componentClass) {
|
|
2252
|
+
return (ctx) => {
|
|
2253
|
+
const hostElement = document.createElement('span');
|
|
2254
|
+
hostElement.style.display = 'contents';
|
|
2255
|
+
const componentRef = createComponent(componentClass, {
|
|
2256
|
+
environmentInjector: this.injector,
|
|
2257
|
+
hostElement,
|
|
2258
|
+
});
|
|
2259
|
+
this.setComponentInputs(componentRef, {
|
|
2260
|
+
totalRows: ctx.totalRows,
|
|
2261
|
+
filteredRows: ctx.filteredRows,
|
|
2262
|
+
selectedRows: ctx.selectedRows,
|
|
2263
|
+
columns: ctx.columns,
|
|
2264
|
+
rows: ctx.rows,
|
|
2265
|
+
grid: ctx.grid,
|
|
2266
|
+
});
|
|
2267
|
+
this.appRef.attachView(componentRef.hostView);
|
|
2268
|
+
this.componentRefs.push(componentRef);
|
|
2269
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
2270
|
+
return hostElement;
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Creates a loading renderer function from an Angular component class.
|
|
2275
|
+
*
|
|
2276
|
+
* The component should accept a `size` input ('large' | 'small').
|
|
2277
|
+
* @internal
|
|
2278
|
+
*/
|
|
2279
|
+
createComponentLoadingRenderer(componentClass) {
|
|
2280
|
+
return (ctx) => {
|
|
2281
|
+
const hostElement = document.createElement('span');
|
|
2282
|
+
hostElement.style.display = 'contents';
|
|
2283
|
+
const componentRef = createComponent(componentClass, {
|
|
2284
|
+
environmentInjector: this.injector,
|
|
2285
|
+
hostElement,
|
|
2286
|
+
});
|
|
2287
|
+
this.setComponentInputs(componentRef, {
|
|
2288
|
+
size: ctx.size,
|
|
2289
|
+
});
|
|
2290
|
+
this.appRef.attachView(componentRef.hostView);
|
|
2291
|
+
this.componentRefs.push(componentRef);
|
|
2292
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
2293
|
+
return hostElement;
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
/**
|
|
2297
|
+
* Creates a group row renderer function from an Angular component class.
|
|
2298
|
+
*
|
|
2299
|
+
* The component should accept group row inputs (key, value, depth, rows, expanded, toggleExpand).
|
|
2300
|
+
* Returns the host element directly (groupRowRenderer returns an element, not void).
|
|
2301
|
+
* @internal
|
|
2302
|
+
*/
|
|
2303
|
+
createComponentGroupRowRenderer(componentClass) {
|
|
2304
|
+
return (params) => {
|
|
2305
|
+
const hostElement = document.createElement('span');
|
|
2306
|
+
hostElement.style.display = 'contents';
|
|
2307
|
+
const componentRef = createComponent(componentClass, {
|
|
2308
|
+
environmentInjector: this.injector,
|
|
2309
|
+
hostElement,
|
|
2310
|
+
});
|
|
2311
|
+
this.setComponentInputs(componentRef, {
|
|
2312
|
+
key: params.key,
|
|
2313
|
+
value: params.value,
|
|
2314
|
+
depth: params.depth,
|
|
2315
|
+
rows: params.rows,
|
|
2316
|
+
expanded: params.expanded,
|
|
2317
|
+
toggleExpand: params.toggleExpand,
|
|
2318
|
+
});
|
|
2319
|
+
this.appRef.attachView(componentRef.hostView);
|
|
2320
|
+
this.componentRefs.push(componentRef);
|
|
2321
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
2322
|
+
return hostElement;
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2097
2325
|
/**
|
|
2098
2326
|
* Creates a filter panel renderer function from an Angular component class.
|
|
2099
2327
|
*
|
|
@@ -2580,7 +2808,7 @@ function injectGrid() {
|
|
|
2580
2808
|
* ## Usage
|
|
2581
2809
|
*
|
|
2582
2810
|
* ```typescript
|
|
2583
|
-
* import { Component } from '@angular/core';
|
|
2811
|
+
* import { Component, viewChild, ElementRef } from '@angular/core';
|
|
2584
2812
|
* import { BaseFilterPanel } from '@toolbox-web/grid-angular';
|
|
2585
2813
|
*
|
|
2586
2814
|
* @Component({
|
|
@@ -2592,10 +2820,10 @@ function injectGrid() {
|
|
|
2592
2820
|
* `
|
|
2593
2821
|
* })
|
|
2594
2822
|
* export class TextFilterComponent extends BaseFilterPanel {
|
|
2595
|
-
*
|
|
2823
|
+
* input = viewChild.required<ElementRef<HTMLInputElement>>('input');
|
|
2596
2824
|
*
|
|
2597
2825
|
* applyFilter(): void {
|
|
2598
|
-
* this.params().applyTextFilter('contains', this.input.nativeElement.value);
|
|
2826
|
+
* this.params().applyTextFilter('contains', this.input().nativeElement.value);
|
|
2599
2827
|
* }
|
|
2600
2828
|
* }
|
|
2601
2829
|
* ```
|
|
@@ -3188,7 +3416,7 @@ let anchorCounter = 0;
|
|
|
3188
3416
|
* ## Usage
|
|
3189
3417
|
*
|
|
3190
3418
|
* ```typescript
|
|
3191
|
-
* import { Component,
|
|
3419
|
+
* import { Component, viewChild, ElementRef, effect } from '@angular/core';
|
|
3192
3420
|
* import { BaseOverlayEditor } from '@toolbox-web/grid-angular';
|
|
3193
3421
|
*
|
|
3194
3422
|
* @Component({
|
|
@@ -3211,18 +3439,22 @@ let anchorCounter = 0;
|
|
|
3211
3439
|
* `
|
|
3212
3440
|
* })
|
|
3213
3441
|
* export class DateEditorComponent extends BaseOverlayEditor<MyRow, string> {
|
|
3214
|
-
*
|
|
3215
|
-
*
|
|
3442
|
+
* panelRef = viewChild.required<ElementRef<HTMLElement>>('panel');
|
|
3443
|
+
* inputRef = viewChild.required<ElementRef<HTMLInputElement>>('inlineInput');
|
|
3216
3444
|
*
|
|
3217
3445
|
* protected override overlayPosition = 'below' as const;
|
|
3218
3446
|
*
|
|
3219
|
-
*
|
|
3220
|
-
*
|
|
3221
|
-
*
|
|
3447
|
+
* constructor() {
|
|
3448
|
+
* super();
|
|
3449
|
+
* effect(() => {
|
|
3450
|
+
* const panel = this.panelRef().nativeElement;
|
|
3451
|
+
* this.initOverlay(panel);
|
|
3452
|
+
* if (this.isCellFocused()) this.showOverlay();
|
|
3453
|
+
* });
|
|
3222
3454
|
* }
|
|
3223
3455
|
*
|
|
3224
3456
|
* protected getInlineInput(): HTMLInputElement | null {
|
|
3225
|
-
* return this.inputRef?.nativeElement ?? null;
|
|
3457
|
+
* return this.inputRef()?.nativeElement ?? null;
|
|
3226
3458
|
* }
|
|
3227
3459
|
*
|
|
3228
3460
|
* protected onOverlayOutsideClick(): void {
|
|
@@ -3283,7 +3515,7 @@ class BaseOverlayEditor extends BaseGridEditor {
|
|
|
3283
3515
|
/**
|
|
3284
3516
|
* Initialise the overlay with the panel element.
|
|
3285
3517
|
*
|
|
3286
|
-
* Call this in `
|
|
3518
|
+
* Call this in an `effect()` or `afterNextRender()` with your `viewChild` panel reference.
|
|
3287
3519
|
* The panel is moved to `<body>` and hidden until {@link showOverlay} is called.
|
|
3288
3520
|
*
|
|
3289
3521
|
* @param panel - The overlay panel DOM element
|
|
@@ -4765,7 +4997,7 @@ class Grid {
|
|
|
4765
4997
|
*
|
|
4766
4998
|
* @example
|
|
4767
4999
|
* ```html
|
|
4768
|
-
* <tbw-grid [groupingColumns]="
|
|
5000
|
+
* <tbw-grid [groupingColumns]="true" />
|
|
4769
5001
|
* ```
|
|
4770
5002
|
*/
|
|
4771
5003
|
groupingColumns = input(...(ngDevMode ? [undefined, { debugName: "groupingColumns" }] : []));
|
|
@@ -5311,11 +5543,32 @@ class Grid {
|
|
|
5311
5543
|
addPlugin('reorderColumns', this.reorderColumns() ?? this.reorder());
|
|
5312
5544
|
addPlugin('visibility', this.visibility());
|
|
5313
5545
|
addPlugin('pinnedColumns', this.pinnedColumns());
|
|
5314
|
-
|
|
5546
|
+
// Pre-process groupingColumns config to bridge Angular component classes
|
|
5547
|
+
const gcConfig = this.groupingColumns();
|
|
5548
|
+
if (gcConfig && typeof gcConfig === 'object' && this.adapter) {
|
|
5549
|
+
addPlugin('groupingColumns', this.adapter.processGroupingColumnsConfig(gcConfig));
|
|
5550
|
+
}
|
|
5551
|
+
else {
|
|
5552
|
+
addPlugin('groupingColumns', gcConfig);
|
|
5553
|
+
}
|
|
5315
5554
|
addPlugin('columnVirtualization', this.columnVirtualization());
|
|
5316
5555
|
addPlugin('reorderRows', this.reorderRows() ?? this.rowReorder());
|
|
5317
|
-
|
|
5318
|
-
|
|
5556
|
+
// Pre-process groupingRows config to bridge Angular component classes
|
|
5557
|
+
const grConfig = this.groupingRows();
|
|
5558
|
+
if (grConfig && typeof grConfig === 'object' && this.adapter) {
|
|
5559
|
+
addPlugin('groupingRows', this.adapter.processGroupingRowsConfig(grConfig));
|
|
5560
|
+
}
|
|
5561
|
+
else {
|
|
5562
|
+
addPlugin('groupingRows', grConfig);
|
|
5563
|
+
}
|
|
5564
|
+
// Pre-process pinnedRows config to bridge Angular component classes in customPanels
|
|
5565
|
+
const prConfig = this.pinnedRows();
|
|
5566
|
+
if (prConfig && typeof prConfig === 'object' && this.adapter) {
|
|
5567
|
+
addPlugin('pinnedRows', this.adapter.processPinnedRowsConfig(prConfig));
|
|
5568
|
+
}
|
|
5569
|
+
else {
|
|
5570
|
+
addPlugin('pinnedRows', prConfig);
|
|
5571
|
+
}
|
|
5319
5572
|
addPlugin('tree', this.tree());
|
|
5320
5573
|
addPlugin('masterDetail', this.masterDetail());
|
|
5321
5574
|
addPlugin('responsive', this.responsive());
|