@one-paragon/angular-utilities 2.8.2 → 2.8.4
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/karma.conf.js +43 -0
- package/ng-package.json +7 -0
- package/package.json +15 -27
- package/src/action-state/action-state-spinner/action-state-spinner.component.css +16 -0
- package/src/action-state/action-state-spinner/action-state-spinner.component.html +7 -0
- package/src/action-state/action-state-spinner/action-state-spinner.component.spec.ts +25 -0
- package/src/action-state/action-state-spinner/action-state-spinner.component.ts +26 -0
- package/src/action-state/action-state-ui/action-state-ui.module.ts +13 -0
- package/src/action-state/index.ts +8 -0
- package/src/action-state/ngrx-ext/ngrx-ext.module.ts +14 -0
- package/src/action-state/ngrx.ts +69 -0
- package/src/http-request-state/RequestStateFactory.ts +56 -0
- package/src/http-request-state/RequestStateStore.ts +360 -0
- package/src/http-request-state/deprecated.ts +20 -0
- package/src/http-request-state/directives/HttpStateDirectiveBase.ts +29 -0
- package/src/http-request-state/directives/http-error-state-directive.ts +21 -0
- package/src/http-request-state/directives/http-inProgress-state-directive.ts +19 -0
- package/src/http-request-state/directives/http-notStarted-state-directive.ts +19 -0
- package/src/http-request-state/directives/http-success-state-directive.ts +29 -0
- package/src/http-request-state/directives/index.ts +5 -0
- package/src/http-request-state/directives/request-state-directive.spec.ts +73 -0
- package/src/http-request-state/directives/request-state-directive.ts +78 -0
- package/src/http-request-state/documentation/CREATE-REQUESTOR.md +667 -0
- package/src/http-request-state/documentation/README.md +191 -0
- package/src/http-request-state/documentation/REQUEST-STATE-STORE-CONFIG.md +648 -0
- package/src/http-request-state/documentation/REQUESTOR.md +616 -0
- package/src/http-request-state/helpers.ts +30 -0
- package/src/http-request-state/http-state-module.ts +23 -0
- package/src/http-request-state/index.ts +7 -0
- package/src/http-request-state/models/view-context.ts +18 -0
- package/src/http-request-state/observable.spec.ts +43 -0
- package/src/http-request-state/request-state.ts +66 -0
- package/src/http-request-state/rxjs/getRequestorBody.ts +10 -0
- package/src/http-request-state/rxjs/getRequestorState.ts +8 -0
- package/src/http-request-state/rxjs/index.ts +4 -0
- package/src/http-request-state/rxjs/tapError.ts +16 -0
- package/src/http-request-state/rxjs/tapSuccess.ts +16 -0
- package/src/http-request-state/strategies.spec.ts +42 -0
- package/src/http-request-state/types.ts +54 -0
- package/src/ngrx/actionable-selector.ts +189 -0
- package/src/ngrx/index.ts +1 -0
- package/src/public-api.ts +40 -0
- package/src/rxjs/defaultShareReplay.ts +8 -0
- package/src/rxjs/index.ts +5 -0
- package/src/rxjs/mapError.ts +8 -0
- package/src/rxjs/rxjs-operators.ts +130 -0
- package/src/rxjs/subjectifier.ts +17 -0
- package/src/rxjs/subscriber.directive.ts +57 -0
- package/src/specs/clickSubject.spec.ts +99 -0
- package/src/specs/dialog.spec.ts +101 -0
- package/src/specs/toggleGroupDirective.spec.ts +229 -0
- package/src/table-builder/classes/DefaultSettings.ts +11 -0
- package/src/table-builder/classes/MatTableObservableDataSource.ts +23 -0
- package/src/table-builder/classes/TableBuilderConfig.ts +49 -0
- package/src/table-builder/classes/TableBuilderDataSource.ts +64 -0
- package/src/table-builder/classes/TableState.ts +96 -0
- package/src/table-builder/classes/data-store.ts +10 -0
- package/src/table-builder/classes/display-col.ts +5 -0
- package/src/table-builder/classes/filter-info.ts +129 -0
- package/src/table-builder/classes/table-builder-general-settings.ts +233 -0
- package/src/table-builder/classes/table-builder.ts +105 -0
- package/src/table-builder/classes/table-store.helpers.ts +109 -0
- package/src/table-builder/classes/table-store.ts +540 -0
- package/src/table-builder/components/array-column.component.ts +34 -0
- package/src/table-builder/components/column-builder/column-builder.component.html +109 -0
- package/src/table-builder/components/column-builder/column-builder.component.scss +43 -0
- package/src/table-builder/components/column-builder/column-builder.component.spec.ts +49 -0
- package/src/table-builder/components/column-builder/column-builder.component.ts +130 -0
- package/src/table-builder/components/column-builder/column-helpers.ts +54 -0
- package/src/table-builder/components/column-header-menu/column-header-menu.component.html +128 -0
- package/src/table-builder/components/column-header-menu/column-header-menu.component.scss +97 -0
- package/src/table-builder/components/column-header-menu/column-header-menu.component.ts +113 -0
- package/src/table-builder/components/date-filter/date-filter.component.html +39 -0
- package/src/table-builder/components/date-filter/date-filter.component.ts +33 -0
- package/src/table-builder/components/date-time-filter/date-time-filter.component.html +25 -0
- package/src/table-builder/components/date-time-filter/date-time-filter.component.ts +33 -0
- package/src/table-builder/components/filter/filter.component.html +120 -0
- package/src/table-builder/components/filter/filter.component.scss +60 -0
- package/src/table-builder/components/filter/filter.component.spec.ts +86 -0
- package/src/table-builder/components/filter/filter.component.ts +73 -0
- package/src/table-builder/components/filter/in-list/in-list-filter.component.ts +171 -0
- package/src/table-builder/components/gen-col-displayer/gen-col-displayer.component.html +60 -0
- package/src/table-builder/components/gen-col-displayer/gen-col-displayer.component.scss +57 -0
- package/src/table-builder/components/gen-col-displayer/gen-col-displayer.component.ts +44 -0
- package/src/table-builder/components/generic-table/generic-table.component.html +140 -0
- package/src/table-builder/components/generic-table/generic-table.component.scss +45 -0
- package/src/table-builder/components/generic-table/generic-table.component.ts +531 -0
- package/src/table-builder/components/generic-table/paginator.component.ts +125 -0
- package/src/table-builder/components/group-by-list/group-by-list.component.css +24 -0
- package/src/table-builder/components/group-by-list/group-by-list.component.html +21 -0
- package/src/table-builder/components/group-by-list/group-by-list.component.spec.ts +23 -0
- package/src/table-builder/components/group-by-list/group-by-list.component.ts +26 -0
- package/src/table-builder/components/in-filter/in-filter.component.css +22 -0
- package/src/table-builder/components/in-filter/in-filter.component.html +38 -0
- package/src/table-builder/components/in-filter/in-filter.component.ts +66 -0
- package/src/table-builder/components/index.ts +9 -0
- package/src/table-builder/components/initialization-component/initialization.component.html +78 -0
- package/src/table-builder/components/initialization-component/initialization.component.ts +28 -0
- package/src/table-builder/components/link-column.component.ts +42 -0
- package/src/table-builder/components/number-filter/number-filter.component.css +10 -0
- package/src/table-builder/components/number-filter/number-filter.component.html +32 -0
- package/src/table-builder/components/number-filter/number-filter.component.spec.ts +30 -0
- package/src/table-builder/components/number-filter/number-filter.component.ts +34 -0
- package/src/table-builder/components/profiles-menu/profiles-menu.component.html +77 -0
- package/src/table-builder/components/profiles-menu/profiles-menu.component.scss +126 -0
- package/src/table-builder/components/profiles-menu/profiles-menu.component.spec.ts +23 -0
- package/src/table-builder/components/profiles-menu/profiles-menu.component.ts +64 -0
- package/src/table-builder/components/reset-menu/reset-menu.component.css +3 -0
- package/src/table-builder/components/reset-menu/reset-menu.component.html +10 -0
- package/src/table-builder/components/reset-menu/reset-menu.component.ts +87 -0
- package/src/table-builder/components/scroll-strategy.ts +139 -0
- package/src/table-builder/components/sort-menu/sort-menu.component-store.ts +57 -0
- package/src/table-builder/components/sort-menu/sort-menu.component.html +115 -0
- package/src/table-builder/components/sort-menu/sort-menu.component.scss +119 -0
- package/src/table-builder/components/sort-menu/sort-menu.component.ts +88 -0
- package/src/table-builder/components/table-container/table-container.component.html +94 -0
- package/src/table-builder/components/table-container/table-container.component.scss +60 -0
- package/src/table-builder/components/table-container/table-container.component.ts +467 -0
- package/src/table-builder/components/table-container/table-container.helpers/data-state.helpers.ts +113 -0
- package/src/table-builder/components/table-container/table-container.helpers/filter-state.helpers.ts +125 -0
- package/src/table-builder/components/table-container/table-container.helpers/groupBy.helpers.ts +172 -0
- package/src/table-builder/components/table-container/table-container.helpers/meta-data.helpers.ts +19 -0
- package/src/table-builder/components/table-container/table-container.helpers/sort-state.helpers.ts +47 -0
- package/src/table-builder/components/table-container/tableProps.ts +21 -0
- package/src/table-builder/components/table-container/virtual-scroll-container.ts +216 -0
- package/src/table-builder/components/table-container-filter/filter-list/filter-list.component.html +42 -0
- package/src/table-builder/components/table-container-filter/filter-list/filter-list.component.ts +47 -0
- package/src/table-builder/components/table-container-filter/gen-filter-displayer/gen-filter-displayer.component.css +40 -0
- package/src/table-builder/components/table-container-filter/gen-filter-displayer/gen-filter-displayer.component.html +11 -0
- package/src/table-builder/components/table-container-filter/gen-filter-displayer/gen-filter-displayer.component.spec.ts +85 -0
- package/src/table-builder/components/table-container-filter/gen-filter-displayer/gen-filter-displayer.component.ts +35 -0
- package/src/table-builder/components/table-container-filter/table-wrapper-filter-store.ts +13 -0
- package/src/table-builder/components/table-header-menu/table-header-menu.component.css +21 -0
- package/src/table-builder/components/table-header-menu/table-header-menu.component.html +48 -0
- package/src/table-builder/components/table-header-menu/table-header-menu.component.ts +36 -0
- package/src/table-builder/directives/custom-cell-directive.ts +63 -0
- package/src/table-builder/directives/custom-header-directive.ts +16 -0
- package/src/table-builder/directives/group-row-directive.ts +91 -0
- package/src/table-builder/directives/index.ts +8 -0
- package/src/table-builder/directives/multi-sort.directive.spec.ts +124 -0
- package/src/table-builder/directives/multi-sort.directive.ts +58 -0
- package/src/table-builder/directives/resize-column.directive.ts +107 -0
- package/src/table-builder/directives/table-wrapper.directive.ts +13 -0
- package/src/table-builder/directives/tb-filter.directive.ts +376 -0
- package/src/table-builder/documentation/table-builder/CUSTOM-CELL.md +568 -0
- package/src/table-builder/documentation/table-builder/CUSTOM-GROUP-ROW.md +356 -0
- package/src/table-builder/documentation/table-builder/METADATA-DOCUMENTATION.md +517 -0
- package/src/table-builder/documentation/table-builder/STYLER-STYLE.md +228 -0
- package/src/table-builder/documentation/table-builder/TABLE-BUILDER-CONFIG.md +325 -0
- package/src/table-builder/documentation/table-builder/TABLE-BUILDER-SETTINGS.md +515 -0
- package/src/table-builder/documentation/table-builder/TABLE-BUILDER.md +430 -0
- package/src/table-builder/documentation/table-builder/TABLE-CONTAINER.md +628 -0
- package/src/table-builder/enums/filterTypes.ts +39 -0
- package/src/table-builder/functions/boolean-filter-function.ts +12 -0
- package/src/table-builder/functions/date-filter-function.ts +85 -0
- package/src/table-builder/functions/download-data.ts +11 -0
- package/src/table-builder/functions/null-filter-function.ts +9 -0
- package/src/table-builder/functions/number-filter-function.ts +47 -0
- package/src/table-builder/functions/sort-data-function.ts +80 -0
- package/src/table-builder/functions/string-filter-function.ts +59 -0
- package/src/table-builder/interfaces/ColumnInfo.ts +9 -0
- package/src/table-builder/interfaces/dictionary.ts +3 -0
- package/src/table-builder/interfaces/meta-data.ts +279 -0
- package/src/table-builder/ngrx/tableBuilderStateStore.ts +203 -0
- package/src/table-builder/pipes/column-total.pipe.ts +16 -0
- package/src/table-builder/pipes/format-filter-type.pipe.ts +12 -0
- package/src/table-builder/pipes/format-filter-value.pipe.ts +71 -0
- package/src/table-builder/pipes/key-display.ts +13 -0
- package/src/table-builder/services/all-values-filter-creator.service.ts +92 -0
- package/src/table-builder/services/export-to-csv.service.ts +117 -0
- package/src/table-builder/services/link-creator.service.ts +98 -0
- package/src/table-builder/services/table-template-service.ts +47 -0
- package/src/table-builder/services/transform-creator.ts +90 -0
- package/src/table-builder/specs/table-custom-filters.spec.ts +262 -0
- package/src/table-builder/styles/collapser.styles.scss +16 -0
- package/src/table-builder/table-builder.module.ts +42 -0
- package/src/table-builder/types/group-types.ts +42 -0
- package/src/table-builder/types/index.ts +1 -0
- package/src/test.ts +17 -0
- package/src/utilities/array-helpers.ts +13 -0
- package/src/utilities/directives/auto-focus.directive.ts +20 -0
- package/src/utilities/directives/clickEmitterDirective.ts +15 -0
- package/src/utilities/directives/clickSubject.ts +19 -0
- package/src/utilities/directives/conditional-classes.directive.ts +36 -0
- package/src/utilities/directives/dialog-service.ts +19 -0
- package/src/utilities/directives/dialog.ts +174 -0
- package/src/utilities/directives/mat-toggle-group-directive.ts +60 -0
- package/src/utilities/directives/prevent-enter.directive.ts +12 -0
- package/src/utilities/directives/stop-propagation.directive.ts +19 -0
- package/src/utilities/directives/styler.ts +45 -0
- package/src/utilities/directives/trim-whitespace.directive.ts +20 -0
- package/src/utilities/index.ts +22 -0
- package/src/utilities/module.ts +53 -0
- package/src/utilities/pipes/function.pipe.ts +21 -0
- package/src/utilities/pipes/phone.pipe.ts +20 -0
- package/src/utilities/pipes/space-case.pipes.spec.ts +47 -0
- package/src/utilities/pipes/space-case.pipes.ts +29 -0
- package/tsconfig.lib.json +20 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +17 -0
- package/fesm2022/one-paragon-angular-utilities.mjs +0 -7328
- package/fesm2022/one-paragon-angular-utilities.mjs.map +0 -1
- package/types/one-paragon-angular-utilities.d.ts +0 -2197
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
# CustomCell Directive Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `customCell` directive allows you to provide custom templates for rendering table cells. This is useful when you need to display formatted data, add interactive elements, or create complex cell layouts that go beyond simple text display.
|
|
6
|
+
|
|
7
|
+
> **💡 Type Safety Recommendation**: For better TypeScript support and type inference in your templates, it's recommended to use the `tableRef` input parameter. See [customCellTableRef](#customcelltableref) for details.
|
|
8
|
+
|
|
9
|
+
## Basic Usage
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Component } from '@angular/core';
|
|
13
|
+
import { TableBuilder, FieldType, CustomCellDirective } from 'angular-utilities';
|
|
14
|
+
import { TableContainerComponent } from 'angular-utilities';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: 'app-users-table',
|
|
18
|
+
standalone: true,
|
|
19
|
+
imports: [TableContainerComponent, CustomCellDirective],
|
|
20
|
+
template: `
|
|
21
|
+
<tb-table-container [tableBuilder]="tableBuilder">
|
|
22
|
+
<!-- Custom cell template -->
|
|
23
|
+
<p *customCell="'status'; let row">
|
|
24
|
+
<span [class]="'status-badge status-' + row.status">
|
|
25
|
+
{{ row.status }}
|
|
26
|
+
</span>
|
|
27
|
+
</p>
|
|
28
|
+
</tb-table-container>
|
|
29
|
+
`
|
|
30
|
+
})
|
|
31
|
+
export class UsersTableComponent {
|
|
32
|
+
users = [
|
|
33
|
+
{ id: 1, name: 'John Doe', status: 'active' },
|
|
34
|
+
{ id: 2, name: 'Jane Smith', status: 'inactive' }
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
tableBuilder = new TableBuilder(this.users);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Template Context
|
|
42
|
+
|
|
43
|
+
The custom cell template receives the following context:
|
|
44
|
+
|
|
45
|
+
### `$implicit` (default)
|
|
46
|
+
- **Type**: `T` (the row data)
|
|
47
|
+
- **Description**: The entire row object. This is the default context variable.
|
|
48
|
+
|
|
49
|
+
### `element`
|
|
50
|
+
- **Type**: `T` (the row data)
|
|
51
|
+
- **Description**: Alternative named access to the row object.
|
|
52
|
+
|
|
53
|
+
**Example:**
|
|
54
|
+
```typescript
|
|
55
|
+
<!-- Using $implicit (default) -->
|
|
56
|
+
<p *customCell="'name'; let row">
|
|
57
|
+
{{ row.name }}
|
|
58
|
+
</p>
|
|
59
|
+
|
|
60
|
+
<!-- Using named element -->
|
|
61
|
+
<p *customCell="'name'; let element = element">
|
|
62
|
+
{{ element.name }}
|
|
63
|
+
</p>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Directive Inputs
|
|
67
|
+
|
|
68
|
+
### Required Inputs
|
|
69
|
+
|
|
70
|
+
#### `customCell`
|
|
71
|
+
- **Type**: `string`
|
|
72
|
+
- **Required**: Yes
|
|
73
|
+
- **Description**: The key/name of the column. This must match either:
|
|
74
|
+
- A property key in your data objects
|
|
75
|
+
- A column defined in your metadata
|
|
76
|
+
- A completely custom column (when used with `customCellNotMapped`)
|
|
77
|
+
|
|
78
|
+
**Example:**
|
|
79
|
+
```html
|
|
80
|
+
<a *customCell="'email'; let row" [href]="'mailto:' + row.email">
|
|
81
|
+
{{ row.email }}
|
|
82
|
+
</a>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Optional Inputs
|
|
86
|
+
|
|
87
|
+
#### `customCellDisplayName`
|
|
88
|
+
- **Type**: `string | undefined`
|
|
89
|
+
- **Default**: `undefined`
|
|
90
|
+
- **Description**: The display name for the column header. Overrides the `displayName` from metadata if both are provided.
|
|
91
|
+
|
|
92
|
+
**Example:**
|
|
93
|
+
```html
|
|
94
|
+
<p *customCell="'fullName'; displayName: 'Employee Name'; let row">
|
|
95
|
+
{{ row.firstName }} {{ row.lastName }}
|
|
96
|
+
</p>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### `customCellOrder`
|
|
100
|
+
- **Type**: `number | undefined`
|
|
101
|
+
- **Default**: `undefined`
|
|
102
|
+
- **Description**: Controls the column order. Lower numbers appear first. Overrides the `order` from metadata if both are provided.
|
|
103
|
+
|
|
104
|
+
**Example:**
|
|
105
|
+
```html
|
|
106
|
+
<div *customCell="'actions'; order: 999; let row">
|
|
107
|
+
<button (click)="edit(row)">Edit</button>
|
|
108
|
+
</div>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### `customCellWidth`
|
|
112
|
+
- **Type**: `string | undefined`
|
|
113
|
+
- **Default**: `undefined`
|
|
114
|
+
- **Description**: CSS width for the column (e.g., `'150px'`, `'20%'`). Overrides the `width` from metadata if both are provided.
|
|
115
|
+
|
|
116
|
+
**Example:**
|
|
117
|
+
```html
|
|
118
|
+
<span *customCell="'status'; width: '120px'; let row" class="badge">
|
|
119
|
+
{{ row.status }}
|
|
120
|
+
</span>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `customCellNotMapped`
|
|
124
|
+
- **Type**: `boolean`
|
|
125
|
+
- **Default**: `false`
|
|
126
|
+
- **Description**: Set to `true` when the column is not mapped to a property in the data source. This is useful for computed columns or action columns that don't correspond to actual data properties. When `true`, the column will have `FieldType.NotMapped`.
|
|
127
|
+
|
|
128
|
+
**Example:**
|
|
129
|
+
```html
|
|
130
|
+
<!-- Action column not in data -->
|
|
131
|
+
<div *customCell="'actions'; notMapped: true; displayName: 'Actions'; let row">
|
|
132
|
+
<button (click)="edit(row)">Edit</button>
|
|
133
|
+
<button (click)="delete(row)">Delete</button>
|
|
134
|
+
</div>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### `preSort`
|
|
138
|
+
- **Type**: `SortDef | undefined`
|
|
139
|
+
- **Default**: `undefined`
|
|
140
|
+
- **Description**: Defines initial sorting for this column. Overrides the `preSort` from metadata if both are provided.
|
|
141
|
+
|
|
142
|
+
**Example:**
|
|
143
|
+
```typescript
|
|
144
|
+
interface SortDef {
|
|
145
|
+
direction: 'asc' | 'desc';
|
|
146
|
+
priority?: number; // For multi-column sort
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```html
|
|
151
|
+
<p *customCell="'createdDate'; preSort: sortDef; let row">
|
|
152
|
+
{{ row.createdDate | date }}
|
|
153
|
+
</p>
|
|
154
|
+
|
|
155
|
+
<!-- In component -->
|
|
156
|
+
sortDef = { direction: 'desc', priority: 1 };
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### `customCellTableRef`
|
|
160
|
+
- **Type**: `TableBuilder<T> | undefined`
|
|
161
|
+
- **Default**: `undefined`
|
|
162
|
+
- **Description**: Reference to the TableBuilder instance for type safety. This helps TypeScript infer the correct type for the row data in the template.
|
|
163
|
+
|
|
164
|
+
**Example:**
|
|
165
|
+
```typescript
|
|
166
|
+
@Component({
|
|
167
|
+
template: `
|
|
168
|
+
<tb-table-container [tableBuilder]="tableBuilder">
|
|
169
|
+
<p *customCell="'name'; tableRef: tableBuilder; let row">
|
|
170
|
+
<!-- TypeScript now knows row is of type User -->
|
|
171
|
+
{{ row.name }}
|
|
172
|
+
</p>
|
|
173
|
+
</tb-table-container>
|
|
174
|
+
`
|
|
175
|
+
})
|
|
176
|
+
export class UsersTableComponent {
|
|
177
|
+
tableBuilder = new TableBuilder<User>(this.users);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### `templateRef`
|
|
182
|
+
- **Type**: `TemplateRef<any> | undefined`
|
|
183
|
+
- **Default**: Auto-injected from `ng-template`
|
|
184
|
+
- **Description**: The template reference. This is typically auto-injected and doesn't need to be set manually.
|
|
185
|
+
|
|
186
|
+
## Combining MetaData with Custom Cells
|
|
187
|
+
|
|
188
|
+
You can define a column in your metadata **and** provide a custom cell template. When both are present:
|
|
189
|
+
|
|
190
|
+
- **The metadata defines** the column's data behavior (field type, sorting, filtering, etc.)
|
|
191
|
+
- **The custom cell template** defines the visual rendering
|
|
192
|
+
- **Custom cell inputs override** matching metadata properties
|
|
193
|
+
|
|
194
|
+
### Override Priority
|
|
195
|
+
|
|
196
|
+
When a column is defined in both metadata and has a custom cell directive, the directive inputs take precedence:
|
|
197
|
+
|
|
198
|
+
- `customCellDisplayName` → overrides `metaData.displayName`
|
|
199
|
+
- `customCellOrder` → overrides `metaData.order`
|
|
200
|
+
- `customCellWidth` → overrides `metaData.width`
|
|
201
|
+
- `preSort` → overrides `metaData.preSort`
|
|
202
|
+
|
|
203
|
+
### Example: Metadata + Custom Cell
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { Component } from '@angular/core';
|
|
207
|
+
import { TableBuilder, FieldType } from 'angular-utilities';
|
|
208
|
+
|
|
209
|
+
interface User {
|
|
210
|
+
id: number;
|
|
211
|
+
name: string;
|
|
212
|
+
email: string;
|
|
213
|
+
salary: number;
|
|
214
|
+
status: 'active' | 'inactive' | 'pending';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@Component({
|
|
218
|
+
selector: 'app-users-table',
|
|
219
|
+
standalone: true,
|
|
220
|
+
imports: [TableContainerComponent, CustomCellDirective],
|
|
221
|
+
template: `
|
|
222
|
+
<tb-table-container [tableBuilder]="tableBuilder">
|
|
223
|
+
<!-- Email column: metadata defines behavior, custom cell defines rendering -->
|
|
224
|
+
<a *customCell="'email'; let row"
|
|
225
|
+
[href]="'mailto:' + row.email"
|
|
226
|
+
class="email-link">
|
|
227
|
+
<mat-icon>email</mat-icon>
|
|
228
|
+
{{ row.email }}
|
|
229
|
+
</a>
|
|
230
|
+
|
|
231
|
+
<!-- Status column: override display name from metadata -->
|
|
232
|
+
<span *customCell="'status'; displayName: 'Account Status'; let row"
|
|
233
|
+
[class]="'status-badge status-' + row.status">
|
|
234
|
+
{{ row.status | titlecase }}
|
|
235
|
+
</span>
|
|
236
|
+
|
|
237
|
+
<!-- Salary column: metadata provides formatting, custom cell adds styling -->
|
|
238
|
+
<span *customCell="'salary'; let row"
|
|
239
|
+
[class.high-salary]="row.salary > 100000">
|
|
240
|
+
{{ row.salary | currency }}
|
|
241
|
+
</span>
|
|
242
|
+
</tb-table-container>
|
|
243
|
+
`
|
|
244
|
+
})
|
|
245
|
+
export class UsersTableComponent {
|
|
246
|
+
users: User[] = [
|
|
247
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', salary: 95000, status: 'active' },
|
|
248
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', salary: 120000, status: 'active' }
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
metaData = [
|
|
252
|
+
{
|
|
253
|
+
key: 'id',
|
|
254
|
+
fieldType: FieldType.Number,
|
|
255
|
+
displayName: 'ID',
|
|
256
|
+
width: '80px'
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
key: 'name',
|
|
260
|
+
fieldType: FieldType.String,
|
|
261
|
+
displayName: 'Name'
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
key: 'email',
|
|
265
|
+
fieldType: FieldType.String,
|
|
266
|
+
displayName: 'Email',
|
|
267
|
+
width: '250px'
|
|
268
|
+
// Custom cell provides the template, but this metadata defines:
|
|
269
|
+
// - Field type (enables proper sorting/filtering)
|
|
270
|
+
// - Default display name (can be overridden by customCellDisplayName)
|
|
271
|
+
// - Width (can be overridden by customCellWidth)
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
key: 'salary',
|
|
275
|
+
fieldType: FieldType.Currency,
|
|
276
|
+
displayName: 'Salary',
|
|
277
|
+
width: '120px'
|
|
278
|
+
// FieldType.Currency enables currency-aware sorting
|
|
279
|
+
// Custom cell adds conditional styling
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
key: 'status',
|
|
283
|
+
fieldType: FieldType.String,
|
|
284
|
+
displayName: 'Status', // Will be overridden by customCellDisplayName
|
|
285
|
+
order: 50
|
|
286
|
+
}
|
|
287
|
+
];
|
|
288
|
+
|
|
289
|
+
tableBuilder = new TableBuilder(this.users, this.metaData);
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Use Cases
|
|
294
|
+
|
|
295
|
+
### 1. Action Columns
|
|
296
|
+
|
|
297
|
+
```html
|
|
298
|
+
<div *customCell="'actions'; notMapped: true; displayName: 'Actions'; width: '150px'; order: 999; let row">
|
|
299
|
+
<button mat-icon-button (click)="edit(row)">
|
|
300
|
+
<mat-icon>edit</mat-icon>
|
|
301
|
+
</button>
|
|
302
|
+
<button mat-icon-button (click)="delete(row)">
|
|
303
|
+
<mat-icon>delete</mat-icon>
|
|
304
|
+
</button>
|
|
305
|
+
</div>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 2. Status Badges
|
|
309
|
+
|
|
310
|
+
```html
|
|
311
|
+
<span *customCell="'status'; let row"
|
|
312
|
+
class="status-badge"
|
|
313
|
+
[ngClass]="{
|
|
314
|
+
'status-active': row.status === 'active',
|
|
315
|
+
'status-inactive': row.status === 'inactive',
|
|
316
|
+
'status-pending': row.status === 'pending'
|
|
317
|
+
}">
|
|
318
|
+
{{ row.status | titlecase }}
|
|
319
|
+
</span>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 3. Links
|
|
323
|
+
|
|
324
|
+
```html
|
|
325
|
+
<a *customCell="'name'; let row" [routerLink]="['/users', row.id]">
|
|
326
|
+
{{ row.name }}
|
|
327
|
+
</a>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 4. Images
|
|
331
|
+
|
|
332
|
+
```html
|
|
333
|
+
<img *customCell="'avatar'; width: '80px'; let row"
|
|
334
|
+
[src]="row.avatarUrl"
|
|
335
|
+
[alt]="row.name"
|
|
336
|
+
class="avatar-img">
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 5. Complex Formatting
|
|
340
|
+
|
|
341
|
+
```html
|
|
342
|
+
<div *customCell="'address'; let row" class="address-cell">
|
|
343
|
+
<div>{{ row.street }}</div>
|
|
344
|
+
<div>{{ row.city }}, {{ row.state }} {{ row.zip }}</div>
|
|
345
|
+
</div>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 6. Conditional Display
|
|
349
|
+
|
|
350
|
+
```html
|
|
351
|
+
<span *customCell="'discount'; let row">
|
|
352
|
+
@if (row.discount > 0) {
|
|
353
|
+
<span class="discount">{{ row.discount }}% OFF</span>
|
|
354
|
+
} @else {
|
|
355
|
+
<span class="no-discount">Regular Price</span>
|
|
356
|
+
}
|
|
357
|
+
</span>
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 7. Interactive Elements
|
|
361
|
+
|
|
362
|
+
```html
|
|
363
|
+
<div *customCell="'quantity'; let row">
|
|
364
|
+
<button (click)="decrement(row)">-</button>
|
|
365
|
+
<span>{{ row.quantity }}</span>
|
|
366
|
+
<button (click)="increment(row)">+</button>
|
|
367
|
+
</div>
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### 8. Computed Values
|
|
371
|
+
|
|
372
|
+
```html
|
|
373
|
+
<span *customCell="'fullName'; notMapped: true; displayName: 'Full Name'; let row">
|
|
374
|
+
{{ row.firstName }} {{ row.lastName }}
|
|
375
|
+
</span>
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Important Notes
|
|
379
|
+
|
|
380
|
+
### Export Behavior
|
|
381
|
+
Custom cells are automatically excluded from CSV exports (`noExport: true`). The export will use the raw data value if the column is mapped to a data property, or exclude the column entirely if `customCellNotMapped` is true.
|
|
382
|
+
|
|
383
|
+
### Field Type
|
|
384
|
+
- If `customCellNotMapped` is `true`, the field type is set to `FieldType.NotMapped`
|
|
385
|
+
- Otherwise, it's set to `FieldType.Unknown`
|
|
386
|
+
- When combining with metadata, the metadata's field type takes precedence for sorting/filtering behavior
|
|
387
|
+
|
|
388
|
+
### Type Safety
|
|
389
|
+
For better TypeScript support in templates, use the `customCellTableRef` input:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
<p *customCell="'name'; tableRef: tableBuilder; let row">
|
|
393
|
+
<!-- TypeScript will infer the correct type for 'row' -->
|
|
394
|
+
{{ row.name }}
|
|
395
|
+
</p>
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Complete Example
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
import { Component } from '@angular/core';
|
|
402
|
+
import { TableBuilder, FieldType, CustomCellDirective } from 'angular-utilities';
|
|
403
|
+
import { TableContainerComponent } from 'angular-utilities';
|
|
404
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
405
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
406
|
+
import { RouterLink } from '@angular/router';
|
|
407
|
+
import { DatePipe, CurrencyPipe, TitleCasePipe } from '@angular/common';
|
|
408
|
+
|
|
409
|
+
interface Product {
|
|
410
|
+
id: number;
|
|
411
|
+
name: string;
|
|
412
|
+
price: number;
|
|
413
|
+
category: string;
|
|
414
|
+
stock: number;
|
|
415
|
+
imageUrl: string;
|
|
416
|
+
status: 'available' | 'out-of-stock' | 'discontinued';
|
|
417
|
+
lastUpdated: Date;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
@Component({
|
|
421
|
+
selector: 'app-products-table',
|
|
422
|
+
standalone: true,
|
|
423
|
+
imports: [
|
|
424
|
+
TableContainerComponent,
|
|
425
|
+
CustomCellDirective,
|
|
426
|
+
MatIconModule,
|
|
427
|
+
MatButtonModule,
|
|
428
|
+
RouterLink,
|
|
429
|
+
DatePipe,
|
|
430
|
+
CurrencyPipe,
|
|
431
|
+
TitleCasePipe
|
|
432
|
+
],
|
|
433
|
+
template: `
|
|
434
|
+
<tb-table-container [tableBuilder]="tableBuilder">
|
|
435
|
+
<!-- Image column (not in original data structure) -->
|
|
436
|
+
<img *customCell="'image'; notMapped: true; displayName: 'Product Image'; width: '100px'; order: 0; let row"
|
|
437
|
+
[src]="row.imageUrl"
|
|
438
|
+
[alt]="row.name"
|
|
439
|
+
class="product-image">
|
|
440
|
+
|
|
441
|
+
<!-- Name with link -->
|
|
442
|
+
<a *customCell="'name'; let row" [routerLink]="['/products', row.id]">
|
|
443
|
+
{{ row.name }}
|
|
444
|
+
</a>
|
|
445
|
+
|
|
446
|
+
<!-- Status badge (override display name) -->
|
|
447
|
+
<span *customCell="'status'; displayName: 'Availability'; let row"
|
|
448
|
+
[class]="'status-badge status-' + row.status">
|
|
449
|
+
{{ row.status | titlecase }}
|
|
450
|
+
</span>
|
|
451
|
+
|
|
452
|
+
<!-- Stock with warning indicator -->
|
|
453
|
+
<span *customCell="'stock'; let row" [class.low-stock]="row.stock < 10">
|
|
454
|
+
{{ row.stock }}
|
|
455
|
+
@if (row.stock < 10) {
|
|
456
|
+
<mat-icon class="warning-icon">warning</mat-icon>
|
|
457
|
+
}
|
|
458
|
+
</span>
|
|
459
|
+
|
|
460
|
+
<!-- Actions (not mapped to data) -->
|
|
461
|
+
<div *customCell="'actions'; notMapped: true; displayName: 'Actions'; width: '150px'; order: 999; let row">
|
|
462
|
+
<button mat-icon-button (click)="edit(row)">
|
|
463
|
+
<mat-icon>edit</mat-icon>
|
|
464
|
+
</button>
|
|
465
|
+
<button mat-icon-button (click)="duplicate(row)">
|
|
466
|
+
<mat-icon>content_copy</mat-icon>
|
|
467
|
+
</button>
|
|
468
|
+
<button mat-icon-button (click)="delete(row)" [disabled]="row.status === 'discontinued'">
|
|
469
|
+
<mat-icon>delete</mat-icon>
|
|
470
|
+
</button>
|
|
471
|
+
</div>
|
|
472
|
+
</tb-table-container>
|
|
473
|
+
`,
|
|
474
|
+
styles: [`
|
|
475
|
+
.product-image {
|
|
476
|
+
width: 60px;
|
|
477
|
+
height: 60px;
|
|
478
|
+
object-fit: cover;
|
|
479
|
+
border-radius: 4px;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.status-badge {
|
|
483
|
+
padding: 4px 8px;
|
|
484
|
+
border-radius: 12px;
|
|
485
|
+
font-size: 12px;
|
|
486
|
+
font-weight: 500;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.status-available { background: #e8f5e9; color: #2e7d32; }
|
|
490
|
+
.status-out-of-stock { background: #fff3e0; color: #e65100; }
|
|
491
|
+
.status-discontinued { background: #ffebee; color: #c62828; }
|
|
492
|
+
|
|
493
|
+
.low-stock {
|
|
494
|
+
color: #e65100;
|
|
495
|
+
display: flex;
|
|
496
|
+
align-items: center;
|
|
497
|
+
gap: 4px;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.warning-icon {
|
|
501
|
+
font-size: 16px;
|
|
502
|
+
width: 16px;
|
|
503
|
+
height: 16px;
|
|
504
|
+
}
|
|
505
|
+
`]
|
|
506
|
+
})
|
|
507
|
+
export class ProductsTableComponent {
|
|
508
|
+
products: Product[] = [
|
|
509
|
+
{
|
|
510
|
+
id: 1,
|
|
511
|
+
name: 'Laptop Pro',
|
|
512
|
+
price: 1299.99,
|
|
513
|
+
category: 'Electronics',
|
|
514
|
+
stock: 45,
|
|
515
|
+
imageUrl: '/assets/laptop.jpg',
|
|
516
|
+
status: 'available',
|
|
517
|
+
lastUpdated: new Date('2024-11-15')
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
id: 2,
|
|
521
|
+
name: 'Wireless Mouse',
|
|
522
|
+
price: 29.99,
|
|
523
|
+
category: 'Accessories',
|
|
524
|
+
stock: 5,
|
|
525
|
+
imageUrl: '/assets/mouse.jpg',
|
|
526
|
+
status: 'available',
|
|
527
|
+
lastUpdated: new Date('2024-11-20')
|
|
528
|
+
}
|
|
529
|
+
];
|
|
530
|
+
|
|
531
|
+
metaData = [
|
|
532
|
+
{ key: 'id', fieldType: FieldType.Number, displayName: 'ID', width: '80px', order: 1 },
|
|
533
|
+
{ key: 'name', fieldType: FieldType.String, displayName: 'Product Name', order: 2 },
|
|
534
|
+
{ key: 'price', fieldType: FieldType.Currency, displayName: 'Price', width: '120px', order: 3 },
|
|
535
|
+
{ key: 'category', fieldType: FieldType.String, displayName: 'Category', order: 4 },
|
|
536
|
+
{ key: 'stock', fieldType: FieldType.Number, displayName: 'Stock', width: '100px', order: 5 },
|
|
537
|
+
{ key: 'status', fieldType: FieldType.String, displayName: 'Status', order: 6 },
|
|
538
|
+
{ key: 'lastUpdated', fieldType: FieldType.Date, displayName: 'Last Updated', order: 7 }
|
|
539
|
+
];
|
|
540
|
+
|
|
541
|
+
tableBuilder = new TableBuilder(this.products, this.metaData, {
|
|
542
|
+
tableSettings: {
|
|
543
|
+
tableId: 'products-table',
|
|
544
|
+
trackBy: 'id'
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
edit(product: Product) {
|
|
549
|
+
console.log('Edit:', product);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
duplicate(product: Product) {
|
|
553
|
+
console.log('Duplicate:', product);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
delete(product: Product) {
|
|
557
|
+
console.log('Delete:', product);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
## Related Documentation
|
|
563
|
+
|
|
564
|
+
- [Table Container Component](TABLE-CONTAINER.md) - How to use custom cells with the table container
|
|
565
|
+
- [MetaData Documentation](METADATA-DOCUMENTATION.md) - Column configuration that works with custom cells
|
|
566
|
+
- [TableBuilder Documentation](TABLE-BUILDER.md) - Setting up the table builder
|
|
567
|
+
- [TableBuilder Settings](TABLE-BUILDER-SETTINGS.md) - Table behavior and appearance
|
|
568
|
+
- [CustomGroupRow Directive](CUSTOM-GROUP-ROW.md) - Custom group row templates
|