ng-firebase-table-kxp 1.1.8 → 2.0.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
@@ -5,6 +5,7 @@
5
5
  NG Firebase Table KXP is a production-ready Angular data table created by **KXP Tech** to power enterprise dashboards backed by Firebase Firestore. It wraps complex Firestore querying, pagination, filtering, and material design styling into a plug-and-play module so teams can ship data-rich experiences faster.
6
6
 
7
7
  ## Table of Contents
8
+
8
9
  - [NG Firebase Table KXP](#ng-firebase-table-kxp)
9
10
  - [Table of Contents](#table-of-contents)
10
11
  - [Why Firebase Table KXP](#why-firebase-table-kxp)
@@ -61,47 +62,35 @@ The host application should already depend on:
61
62
  - Firebase stack: `@angular/fire` (7.x) and `firebase` (9.x)
62
63
  - Utilities: `ngx-toastr` (16.x), `moment` (2.29.x)
63
64
 
64
-
65
65
  1. **Import the module**
66
+
66
67
  ```typescript
67
- import { NgFirebaseTableKxpModule } from '@adryanmmm/ng-firebase-table-kxp';
68
+ import { NgFirebaseTableKxpModule } from "@adryanmmm/ng-firebase-table-kxp";
68
69
 
69
70
  @NgModule({
70
- imports: [
71
- BrowserModule,
72
- BrowserAnimationsModule,
73
- AngularFireModule.initializeApp(environment.firebase),
74
- AngularFirestoreModule,
75
- ToastrModule.forRoot(),
76
- NgxMaskModule.forRoot(),
77
- NgFirebaseTableKxpModule
78
- ]
71
+ imports: [BrowserModule, BrowserAnimationsModule, AngularFireModule.initializeApp(environment.firebase), AngularFirestoreModule, ToastrModule.forRoot(), NgxMaskModule.forRoot(), NgFirebaseTableKxpModule],
79
72
  })
80
73
  export class AppModule {}
81
74
  ```
82
75
 
83
76
  2. **Drop the component**
77
+
84
78
  ```typescript
85
79
  @Component({
86
- selector: 'app-users',
87
- template: `
88
- <lib-table
89
- [data]="table"
90
- [downloadTable]="downloadTable">
91
- </lib-table>
92
- `
80
+ selector: "app-users",
81
+ template: ` <lib-table [data]="table" [downloadTable]="downloadTable"> </lib-table> `,
93
82
  })
94
83
  export class UsersComponent {
95
84
  table: TableData = {
96
- name: 'users',
97
- collection: 'users',
98
- collectionRef: this.firestore.collection('users').ref,
85
+ name: "users",
86
+ collection: "users",
87
+ collectionRef: this.firestore.collection("users").ref,
99
88
  pagination: true,
100
89
  download: true,
101
90
  displayedColumns: [
102
- { property: 'name', title: 'Name', isFilterable: true, isSortable: true },
103
- { property: 'email', title: 'Email', isFilterable: true }
104
- ]
91
+ { property: "name", title: "Name", isFilterable: true, isSortable: true },
92
+ { property: "email", title: "Email", isFilterable: true },
93
+ ],
105
94
  };
106
95
 
107
96
  downloadTable = (arrange: any, conditions: any[]) => {
@@ -113,9 +102,10 @@ export class UsersComponent {
113
102
  ```
114
103
 
115
104
  3. **Make sure global styles include**
105
+
116
106
  ```scss
117
- @import '@angular/material/prebuilt-themes/indigo-pink.css';
118
- @import 'ngx-toastr/toastr';
107
+ @import "@angular/material/prebuilt-themes/indigo-pink.css";
108
+ @import "ngx-toastr/toastr";
119
109
  ```
120
110
 
121
111
  ## Configuration Overview
@@ -136,26 +126,27 @@ This section provides detailed documentation for all configuration interfaces av
136
126
 
137
127
  The main configuration object that defines the entire table behavior.
138
128
 
139
- | Property | Type | Required | Description |
140
- |----------|------|----------|-------------|
141
- | `name` | `string` | ✅ | Unique identifier for the table. Used internally for caching and state management. |
142
- | `collection` | `string` | ✅ | Name of the Firestore collection to query. |
143
- | `collectionRef` | `CollectionReference` | ✅ | Reference to the Firestore collection. Use `firestore.collection('name').ref`. |
144
- | `displayedColumns` | `Column[]` | ✅ | Array of column definitions. Defines what data to display and how. See [Column](#column). |
145
- | `pagination` | `boolean` | ✅ | Enable or disable pagination. When `true`, data is loaded in batches. |
146
- | `download` | `boolean` | ✅ | Enable or disable the export/download functionality. |
147
- | `sortBy` | `{field: string, order: OrderByDirection}` | ❌ | Default sorting configuration. `order` can be `'asc'` or `'desc'`. |
148
- | `conditions` | `Condition[]` | ❌ | Array of Firestore where clauses applied before user filters. See [Condition](#condition). |
149
- | `filterFn` | `(item: any) => boolean` | ❌ | Custom client-side filter function. Applied after Firestore queries. |
150
- | `filterableOptions` | `FilterableOption[]` | ❌ | Predefined filter options displayed as buttons. See [FilterableOption](#filterableoption). |
151
- | `url` | `string` | ❌ | Base URL for row navigation. Row clicks navigate to `{url}/{row.id}`. |
152
- | `isNotClickable` | `boolean` | ❌ | When `true`, disables row click navigation. |
153
- | `color` | `{bg: string, text: string}` | ❌ | CSS classes for custom table theming. `bg` for background, `text` for text color. |
154
- | `totalRef` | `{ref: DocumentReference, field: string}[]` | ❌ | References to documents containing total counts. Displayed in the table footer. |
155
- | `actionButton` | `ActionButton` | ❌ | Configuration for a primary action button (e.g., "Add New"). |
156
- | `tabs` | `Tab` | ❌ | Configuration for tabbed data views. See [Tab & TabData](#tab--tabdata). |
129
+ | Property | Type | Required | Description |
130
+ | ------------------- | ------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ |
131
+ | `name` | `string` | ✅ | Unique identifier for the table. Used internally for caching and state management. |
132
+ | `collection` | `string` | ✅ | Name of the Firestore collection to query. |
133
+ | `collectionRef` | `CollectionReference` | ✅ | Reference to the Firestore collection. Use `firestore.collection('name').ref`. |
134
+ | `displayedColumns` | `Column[]` | ✅ | Array of column definitions. Defines what data to display and how. See [Column](#column). |
135
+ | `pagination` | `boolean` | ✅ | Enable or disable pagination. When `true`, data is loaded in batches. |
136
+ | `download` | `boolean` | ✅ | Enable or disable the export/download functionality. |
137
+ | `sortBy` | `{field: string, order: OrderByDirection}` | ❌ | Default sorting configuration. `order` can be `'asc'` or `'desc'`. |
138
+ | `conditions` | `Condition[]` | ❌ | Array of Firestore where clauses applied before user filters. See [Condition](#condition). |
139
+ | `filterFn` | `(item: any) => boolean` | ❌ | Custom client-side filter function. Applied after Firestore queries. |
140
+ | `filterableOptions` | `FilterableOption[]` | ❌ | Predefined filter options displayed as buttons. See [FilterableOption](#filterableoption). |
141
+ | `url` | `string` | ❌ | Base URL for row navigation. Row clicks navigate to `{url}/{row.id}`. |
142
+ | `isNotClickable` | `boolean` | ❌ | When `true`, disables row click navigation. |
143
+ | `color` | `{bg: string, text: string}` | ❌ | CSS classes for custom table theming. `bg` for background, `text` for text color. |
144
+ | `totalRef` | `{ref: DocumentReference, field: string}[]` | ❌ | References to documents containing total counts. Displayed in the table footer. |
145
+ | `actionButton` | `ActionButton` | ❌ | Configuration for a primary action button (e.g., "Add New"). |
146
+ | `tabs` | `Tab` | ❌ | Configuration for tabbed data views. See [Tab & TabData](#tab--tabdata). |
157
147
 
158
148
  **ActionButton Properties:**
149
+
159
150
  - `label` (string): Button text
160
151
  - `routerLink` (string): Navigation route
161
152
  - `icon` (string): CSS class for icon (e.g., FontAwesome)
@@ -164,24 +155,25 @@ The main configuration object that defines the entire table behavior.
164
155
  - `condition` ((row) => boolean): Function to conditionally show the button
165
156
 
166
157
  **Example:**
158
+
167
159
  ```typescript
168
160
  const tableData: TableData = {
169
- name: 'products',
170
- collection: 'products',
171
- collectionRef: this.firestore.collection('products').ref,
161
+ name: "products",
162
+ collection: "products",
163
+ collectionRef: this.firestore.collection("products").ref,
172
164
  pagination: true,
173
165
  download: true,
174
- sortBy: { field: 'createdAt', order: 'desc' },
175
- conditions: [
176
- { operator: '==', firestoreProperty: 'active', dashProperty: true }
166
+ sortBy: { field: "createdAt", order: "desc" },
167
+ conditions: [{ operator: "==", firestoreProperty: "active", dashProperty: true }],
168
+ displayedColumns: [
169
+ /* ... */
177
170
  ],
178
- displayedColumns: [/* ... */],
179
171
  actionButton: {
180
- label: 'Add Product',
181
- routerLink: '/products/new',
182
- icon: 'fa fa-plus',
183
- colorClass: 'bg-blue-500'
184
- }
172
+ label: "Add Product",
173
+ routerLink: "/products/new",
174
+ icon: "fa fa-plus",
175
+ colorClass: "bg-blue-500",
176
+ },
185
177
  };
186
178
  ```
187
179
 
@@ -191,89 +183,93 @@ const tableData: TableData = {
191
183
 
192
184
  Defines how each column is displayed, filtered, and interacted with.
193
185
 
194
- | Property | Type | Required | Description |
195
- |----------|------|----------|-------------|
196
- | `property` | `string` | ✅ | Name of the property in the data object to display. |
197
- | `title` | `string` | ❌ | Column header text. Defaults to `property` if not provided. |
198
- | `charLimit` | `number` | ❌ | Maximum characters to display. Shows tooltip with full text on hover. |
199
- | `pipe` | `PipeTransform` | ❌ | Angular pipe for formatting values (e.g., `DatePipe`, `CurrencyPipe`). |
200
- | `calculateValue` | `(row: any) => any` | ❌ | Function to compute the display value from the row data. |
201
- | `isSortable` | `boolean` | ❌ | Enable sorting for this column. |
202
- | `isFilterable` | `boolean` | ❌ | Enable text-based filtering for this column. |
203
- | `isFilterableByDate` | `boolean` | ❌ | Enable date range filtering. Shows date picker inputs. |
204
- | `filterPredicates` | `string[]` | ❌ | Additional properties to include when filtering this column. |
205
- | `hasLink` | `boolean \| string` | ❌ | Make the cell value a clickable link. If string, uses as the navigation path. |
206
- | `hasDownload` | `boolean \| string` | ❌ | Add download icon to the cell. If string, uses as the download URL property. |
207
- | `arrayField` | `string` | ❌ | When data is an array of objects, specify which field to display. |
208
- | `method` | `(row: any, event?: any) => any` | ❌ | Custom click handler for the cell. |
209
- | `image` | `Image` | ❌ | Configuration for displaying images. See [Image](#image). |
210
- | `iconClass` | `IconClass[]` | ❌ | Array of icon/button configurations for action buttons in the cell. |
211
- | `relation` | `Relation` | ❌ | Configuration for joining related collection data. |
212
- | `queryLength` | `QueryLength` | ❌ | Configuration for counting related documents. |
186
+ | Property | Type | Required | Description |
187
+ | -------------------- | -------------------------------- | -------- | ----------------------------------------------------------------------------- |
188
+ | `property` | `string` | ✅ | Name of the property in the data object to display. |
189
+ | `title` | `string` | ❌ | Column header text. Defaults to `property` if not provided. |
190
+ | `charLimit` | `number` | ❌ | Maximum characters to display. Shows tooltip with full text on hover. |
191
+ | `pipe` | `PipeTransform` | ❌ | Angular pipe for formatting values (e.g., `DatePipe`, `CurrencyPipe`). |
192
+ | `calculateValue` | `(row: any) => any` | ❌ | Function to compute the display value from the row data. |
193
+ | `isSortable` | `boolean` | ❌ | Enable sorting for this column. |
194
+ | `isFilterable` | `boolean` | ❌ | Enable text-based filtering for this column. |
195
+ | `isFilterableByDate` | `boolean` | ❌ | Enable date range filtering. Shows date picker inputs. |
196
+ | `filterPredicates` | `string[]` | ❌ | Additional properties to include when filtering this column. |
197
+ | `hasLink` | `boolean \| string` | ❌ | Make the cell value a clickable link. If string, uses as the navigation path. |
198
+ | `hasDownload` | `boolean \| string` | ❌ | Add download icon to the cell. If string, uses as the download URL property. |
199
+ | `arrayField` | `string` | ❌ | When data is an array of objects, specify which field to display. |
200
+ | `method` | `(row: any, event?: any) => any` | ❌ | Custom click handler for the cell. |
201
+ | `image` | `Image` | ❌ | Configuration for displaying images. See [Image](#image). |
202
+ | `iconClass` | `IconClass[]` | ❌ | Array of icon/button configurations for action buttons in the cell. |
203
+ | `relation` | `Relation` | ❌ | Configuration for joining related collection data. |
204
+ | `queryLength` | `QueryLength` | ❌ | Configuration for counting related documents. |
213
205
 
214
206
  **IconClass Properties:**
207
+
215
208
  - `class` (string): CSS classes for the icon/button
216
209
  - `text` (string): Text to display alongside icon
217
210
  - `condition` ((row) => any): Function to conditionally show the icon
218
211
  - `buttonMethod` ((row, event) => any): Click handler for the icon
219
212
 
220
213
  **Relation Properties:**
214
+
221
215
  - `collection` (string): Name of the related collection
222
216
  - `property` (string): Property in current row containing the related document ID
223
217
  - `newProperty` (string): Property from related document to fetch and display
224
218
 
225
219
  **QueryLength Properties:**
220
+
226
221
  - `collection` (string): Collection to count documents from
227
222
  - `property` (string): Field to match in the query
228
223
  - `operator` (WhereFilterOp): Firestore operator (e.g., `'=='`, `'>'`)
229
224
  - `value` (string): Property from current row to use as query value
230
225
 
231
226
  **Example:**
227
+
232
228
  ```typescript
233
229
  const columns: Column[] = [
234
230
  {
235
- property: 'name',
236
- title: 'Product Name',
231
+ property: "name",
232
+ title: "Product Name",
237
233
  isFilterable: true,
238
234
  isSortable: true,
239
- charLimit: 50
235
+ charLimit: 50,
240
236
  },
241
237
  {
242
- property: 'price',
243
- title: 'Price',
244
- pipe: new CurrencyPipe('en-US'),
245
- isSortable: true
238
+ property: "price",
239
+ title: "Price",
240
+ pipe: new CurrencyPipe("en-US"),
241
+ isSortable: true,
246
242
  },
247
243
  {
248
- property: 'createdAt',
249
- title: 'Created',
250
- pipe: new DatePipe('en-US'),
251
- isFilterableByDate: true
244
+ property: "createdAt",
245
+ title: "Created",
246
+ pipe: new DatePipe("en-US"),
247
+ isFilterableByDate: true,
252
248
  },
253
249
  {
254
- property: 'categoryName',
255
- title: 'Category',
250
+ property: "categoryName",
251
+ title: "Category",
256
252
  relation: {
257
- collection: 'categories',
258
- property: 'categoryId',
259
- newProperty: 'name'
260
- }
253
+ collection: "categories",
254
+ property: "categoryId",
255
+ newProperty: "name",
256
+ },
261
257
  },
262
258
  {
263
- property: 'actions',
264
- title: 'Actions',
259
+ property: "actions",
260
+ title: "Actions",
265
261
  iconClass: [
266
262
  {
267
- class: 'fa fa-edit text-blue-500 cursor-pointer',
268
- buttonMethod: (row) => this.editProduct(row)
263
+ class: "fa fa-edit text-blue-500 cursor-pointer",
264
+ buttonMethod: (row) => this.editProduct(row),
269
265
  },
270
266
  {
271
- class: 'fa fa-trash text-red-500 cursor-pointer',
267
+ class: "fa fa-trash text-red-500 cursor-pointer",
272
268
  buttonMethod: (row) => this.deleteProduct(row),
273
- condition: (row) => row.canDelete === true
274
- }
275
- ]
276
- }
269
+ condition: (row) => row.canDelete === true,
270
+ },
271
+ ],
272
+ },
277
273
  ];
278
274
  ```
279
275
 
@@ -285,37 +281,34 @@ Configure tabbed views for switching between different data sets within the same
285
281
 
286
282
  **Tab Interface:**
287
283
 
288
- | Property | Type | Required | Description |
289
- |----------|------|----------|-------------|
290
- | `method` | `(tab: any, event?: any) => any` | ✅ | Function called when a tab is clicked. Use to switch data or apply filters. |
291
- | `tabsData` | `TabData[]` | ✅ | Array of tab configurations. |
284
+ | Property | Type | Required | Description |
285
+ | ---------- | -------------------------------- | -------- | --------------------------------------------------------------------------- |
286
+ | `method` | `(tab: any, event?: any) => any` | ✅ | Function called when a tab is clicked. Use to switch data or apply filters. |
287
+ | `tabsData` | `TabData[]` | ✅ | Array of tab configurations. |
292
288
 
293
289
  **TabData Interface:**
294
290
 
295
- | Property | Type | Required | Description |
296
- |----------|------|----------|-------------|
297
- | `label` | `string` | ✅ | Text displayed on the tab. |
298
- | `counter` | `number` | ❌ | Optional counter badge displayed next to the label. |
299
- | `counterClass` | `string` | ❌ | CSS class for styling the counter badge. |
291
+ | Property | Type | Required | Description |
292
+ | -------------- | -------- | -------- | --------------------------------------------------- |
293
+ | `label` | `string` | ✅ | Text displayed on the tab. |
294
+ | `counter` | `number` | ❌ | Optional counter badge displayed next to the label. |
295
+ | `counterClass` | `string` | ❌ | CSS class for styling the counter badge. |
300
296
 
301
297
  **Example:**
298
+
302
299
  ```typescript
303
300
  const tableData: TableData = {
304
301
  // ... other config
305
302
  tabs: {
306
303
  method: (tab, event) => {
307
- if (tab.label === 'Active') {
304
+ if (tab.label === "Active") {
308
305
  this.loadActiveProducts();
309
- } else if (tab.label === 'Inactive') {
306
+ } else if (tab.label === "Inactive") {
310
307
  this.loadInactiveProducts();
311
308
  }
312
309
  },
313
- tabsData: [
314
- { label: 'Active', counter: 42, counterClass: 'bg-green-500' },
315
- { label: 'Inactive', counter: 8, counterClass: 'bg-gray-500' },
316
- { label: 'All' }
317
- ]
318
- }
310
+ tabsData: [{ label: "Active", counter: 42, counterClass: "bg-green-500" }, { label: "Inactive", counter: 8, counterClass: "bg-gray-500" }, { label: "All" }],
311
+ },
319
312
  };
320
313
  ```
321
314
 
@@ -325,34 +318,36 @@ const tableData: TableData = {
325
318
 
326
319
  Predefined filter buttons that users can click to apply common filters.
327
320
 
328
- | Property | Type | Required | Description |
329
- |----------|------|----------|-------------|
330
- | `title` | `string` | ✅ | Label for the filter group. |
331
- | `items` | `FilterItem[]` | ✅ | Array of individual filter options. |
321
+ | Property | Type | Required | Description |
322
+ | -------- | -------------- | -------- | ----------------------------------- |
323
+ | `title` | `string` | ✅ | Label for the filter group. |
324
+ | `items` | `FilterItem[]` | ✅ | Array of individual filter options. |
332
325
 
333
326
  **FilterItem Properties:**
327
+
334
328
  - `property` (string): Property to filter on
335
329
  - `value` (string \| boolean): Value to filter by
336
330
  - `label` (string): Text displayed on the filter button
337
331
 
338
332
  **Example:**
333
+
339
334
  ```typescript
340
335
  const filterableOptions: FilterableOption[] = [
341
336
  {
342
- title: 'Status',
337
+ title: "Status",
343
338
  items: [
344
- { property: 'status', value: 'active', label: 'Active' },
345
- { property: 'status', value: 'pending', label: 'Pending' },
346
- { property: 'status', value: 'archived', label: 'Archived' }
347
- ]
339
+ { property: "status", value: "active", label: "Active" },
340
+ { property: "status", value: "pending", label: "Pending" },
341
+ { property: "status", value: "archived", label: "Archived" },
342
+ ],
348
343
  },
349
344
  {
350
- title: 'Category',
345
+ title: "Category",
351
346
  items: [
352
- { property: 'category', value: 'electronics', label: 'Electronics' },
353
- { property: 'category', value: 'clothing', label: 'Clothing' }
354
- ]
355
- }
347
+ { property: "category", value: "electronics", label: "Electronics" },
348
+ { property: "category", value: "clothing", label: "Clothing" },
349
+ ],
350
+ },
356
351
  ];
357
352
  ```
358
353
 
@@ -362,30 +357,31 @@ const filterableOptions: FilterableOption[] = [
362
357
 
363
358
  Firestore `where` clauses that are always applied to queries, before any user filters.
364
359
 
365
- | Property | Type | Required | Description |
366
- |----------|------|----------|-------------|
367
- | `operator` | `WhereFilterOp` | ✅ | Firestore comparison operator: `'=='`, `'!='`, `'<'`, `'<='`, `'>'`, `'>='`, `'array-contains'`, `'in'`, `'array-contains-any'`, `'not-in'`. |
368
- | `firestoreProperty` | `string` | ✅ | Name of the field in Firestore to filter on. |
369
- | `dashProperty` | `string \| string[]` | ✅ | Value or array of values to compare against. Can be a static value or a property name from your component. |
360
+ | Property | Type | Required | Description |
361
+ | ------------------- | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
362
+ | `operator` | `WhereFilterOp` | ✅ | Firestore comparison operator: `'=='`, `'!='`, `'<'`, `'<='`, `'>'`, `'>='`, `'array-contains'`, `'in'`, `'array-contains-any'`, `'not-in'`. |
363
+ | `firestoreProperty` | `string` | ✅ | Name of the field in Firestore to filter on. |
364
+ | `dashProperty` | `string \| string[]` | ✅ | Value or array of values to compare against. Can be a static value or a property name from your component. |
370
365
 
371
366
  **Example:**
367
+
372
368
  ```typescript
373
369
  const conditions: Condition[] = [
374
370
  {
375
- operator: '==',
376
- firestoreProperty: 'tenantId',
377
- dashProperty: this.currentTenantId
371
+ operator: "==",
372
+ firestoreProperty: "tenantId",
373
+ dashProperty: this.currentTenantId,
378
374
  },
379
375
  {
380
- operator: '>=',
381
- firestoreProperty: 'createdAt',
382
- dashProperty: this.startDate
376
+ operator: ">=",
377
+ firestoreProperty: "createdAt",
378
+ dashProperty: this.startDate,
383
379
  },
384
380
  {
385
- operator: 'in',
386
- firestoreProperty: 'status',
387
- dashProperty: ['active', 'pending']
388
- }
381
+ operator: "in",
382
+ firestoreProperty: "status",
383
+ dashProperty: ["active", "pending"],
384
+ },
389
385
  ];
390
386
  ```
391
387
 
@@ -395,13 +391,14 @@ const conditions: Condition[] = [
395
391
 
396
392
  Internal interface used for managing sort and filter state. Automatically handled by the table component.
397
393
 
398
- | Property | Type | Description |
399
- |----------|------|-------------|
400
- | `filters` | `FilterState[]` | Array of active filters per column. |
401
- | `sortBy` | `{field: string, order: OrderByDirection}` | Current sort configuration. |
402
- | `elementId` | `{property: string, value: string}` | Optional identifier for highlighting a specific row. |
394
+ | Property | Type | Description |
395
+ | ----------- | ------------------------------------------ | ---------------------------------------------------- |
396
+ | `filters` | `FilterState[]` | Array of active filters per column. |
397
+ | `sortBy` | `{field: string, order: OrderByDirection}` | Current sort configuration. |
398
+ | `elementId` | `{property: string, value: string}` | Optional identifier for highlighting a specific row. |
403
399
 
404
400
  **FilterState Properties:**
401
+
405
402
  - `arrange` ('ascending' \| 'descending' \| 'filter' \| 'filterByDate' \| 'equals' \| ''): Type of filter/sort applied
406
403
  - `filter` ({property: string, filtering: string}): Text filter configuration
407
404
  - `dateFilter` ({initial: Date, final: Date}): Date range filter
@@ -412,24 +409,25 @@ Internal interface used for managing sort and filter state. Automatically handle
412
409
 
413
410
  Configuration for displaying images in table cells.
414
411
 
415
- | Property | Type | Required | Description |
416
- |----------|------|----------|-------------|
417
- | `class` | `string` | ✅ | CSS classes for styling the image element. |
418
- | `path` | `string` | ❌ | Property name containing the image path/URL in the row data. |
419
- | `url` | `boolean` | ❌ | If `true`, treats the value as a complete URL. Otherwise, constructs path from storage. |
420
- | `default` | `string` | ❌ | Default image URL if the actual image is missing or fails to load. |
412
+ | Property | Type | Required | Description |
413
+ | --------- | --------- | -------- | --------------------------------------------------------------------------------------- |
414
+ | `class` | `string` | ✅ | CSS classes for styling the image element. |
415
+ | `path` | `string` | ❌ | Property name containing the image path/URL in the row data. |
416
+ | `url` | `boolean` | ❌ | If `true`, treats the value as a complete URL. Otherwise, constructs path from storage. |
417
+ | `default` | `string` | ❌ | Default image URL if the actual image is missing or fails to load. |
421
418
 
422
419
  **Example:**
420
+
423
421
  ```typescript
424
422
  const column: Column = {
425
- property: 'avatar',
426
- title: 'Photo',
423
+ property: "avatar",
424
+ title: "Photo",
427
425
  image: {
428
- class: 'w-10 h-10 rounded-full object-cover',
429
- path: 'photoURL',
426
+ class: "w-10 h-10 rounded-full object-cover",
427
+ path: "photoURL",
430
428
  url: true,
431
- default: '/assets/default-avatar.png'
432
- }
429
+ default: "/assets/default-avatar.png",
430
+ },
433
431
  };
434
432
  ```
435
433
 
@@ -449,9 +447,9 @@ The library provides a flexible export system that allows you to download table
449
447
  #### Basic Example
450
448
 
451
449
  ```typescript
452
- import { TableService } from '@adryanmmm/ng-firebase-table-kxp';
453
- import * as XLSX from 'xlsx';
454
- import moment from 'moment';
450
+ import { TableService } from "@adryanmmm/ng-firebase-table-kxp";
451
+ import * as XLSX from "xlsx";
452
+ import moment from "moment";
455
453
 
456
454
  export class UsersComponent {
457
455
  constructor(private tableService: TableService) {}
@@ -460,28 +458,28 @@ export class UsersComponent {
460
458
  downloadTable = async (arrange: Arrange, conditions: Condition[]) => {
461
459
  // 1. Fetch all data with current filters
462
460
  const rawData = await this.tableService.getItemsData(
463
- 'users', // collection name
464
- arrange, // current sort/filter state
465
- conditions // optional where conditions
461
+ "users", // collection name
462
+ arrange, // current sort/filter state
463
+ conditions, // optional where conditions
466
464
  );
467
465
 
468
466
  // 2. Transform data to desired format
469
- const xlsxData = rawData.map(user => ({
470
- 'Name': user.fullName,
471
- 'Email': user.email,
472
- 'Phone': user.phoneNumber,
473
- 'Created': new Date(user.createdAt.seconds * 1000).toLocaleDateString()
467
+ const xlsxData = rawData.map((user) => ({
468
+ Name: user.fullName,
469
+ Email: user.email,
470
+ Phone: user.phoneNumber,
471
+ Created: new Date(user.createdAt.seconds * 1000).toLocaleDateString(),
474
472
  }));
475
473
 
476
474
  // 3. Generate Excel file
477
475
  const worksheet = XLSX.utils.json_to_sheet(xlsxData);
478
476
  const workbook = XLSX.utils.book_new();
479
- XLSX.utils.book_append_sheet(workbook, worksheet, 'Users');
480
-
477
+ XLSX.utils.book_append_sheet(workbook, worksheet, "Users");
478
+
481
479
  // 4. Download file
482
- const fileName = `Users_${moment().format('DD-MM-YYYY-HH-mm-ss')}.xlsx`;
480
+ const fileName = `Users_${moment().format("DD-MM-YYYY-HH-mm-ss")}.xlsx`;
483
481
  XLSX.writeFile(workbook, fileName);
484
- }
482
+ };
485
483
  }
486
484
  ```
487
485
 
@@ -489,42 +487,38 @@ export class UsersComponent {
489
487
 
490
488
  ```typescript
491
489
  downloadOrdersTable = async (arrange: Arrange, conditions: Condition[]) => {
492
- const rawData = await this.tableService.getItemsData(
493
- 'orders',
494
- arrange,
495
- conditions
496
- );
490
+ const rawData = await this.tableService.getItemsData("orders", arrange, conditions);
497
491
 
498
492
  let totalAmount = 0;
499
493
 
500
494
  // Map data and calculate totals
501
- const xlsxData = rawData.map(order => {
495
+ const xlsxData = rawData.map((order) => {
502
496
  totalAmount += order.amount;
503
497
  return {
504
- 'Order ID': order.id,
505
- 'Customer': order.customerName,
506
- 'Amount': order.amount,
507
- 'Date': new Date(order.createdAt.seconds * 1000).toLocaleDateString(),
508
- 'Status': order.status
498
+ "Order ID": order.id,
499
+ Customer: order.customerName,
500
+ Amount: order.amount,
501
+ Date: new Date(order.createdAt.seconds * 1000).toLocaleDateString(),
502
+ Status: order.status,
509
503
  };
510
504
  });
511
505
 
512
506
  // Add totals row
513
507
  xlsxData.push({
514
- 'Order ID': '',
515
- 'Customer': '',
516
- 'Amount': totalAmount,
517
- 'Date': 'TOTAL',
518
- 'Status': ''
508
+ "Order ID": "",
509
+ Customer: "",
510
+ Amount: totalAmount,
511
+ Date: "TOTAL",
512
+ Status: "",
519
513
  });
520
514
 
521
515
  const worksheet = XLSX.utils.json_to_sheet(xlsxData);
522
516
  const workbook = XLSX.utils.book_new();
523
- XLSX.utils.book_append_sheet(workbook, worksheet, 'Orders');
524
-
525
- const fileName = `Orders_${moment().format('DD-MM-YYYY-HH-mm-ss')}.xlsx`;
517
+ XLSX.utils.book_append_sheet(workbook, worksheet, "Orders");
518
+
519
+ const fileName = `Orders_${moment().format("DD-MM-YYYY-HH-mm-ss")}.xlsx`;
526
520
  XLSX.writeFile(workbook, fileName);
527
- }
521
+ };
528
522
  ```
529
523
 
530
524
  #### Filtering Data Before Export
@@ -533,17 +527,17 @@ You can apply additional client-side filters based on user permissions:
533
527
 
534
528
  ```typescript
535
529
  downloadTable = async (arrange: Arrange, conditions: Condition[]) => {
536
- const rawData = await this.tableService.getItemsData('orders', arrange, conditions);
530
+ const rawData = await this.tableService.getItemsData("orders", arrange, conditions);
537
531
 
538
532
  // Filter based on user permissions
539
- const filteredData = rawData.filter(order => {
540
- if (this.currentUser.role === 'Admin') return true;
533
+ const filteredData = rawData.filter((order) => {
534
+ if (this.currentUser.role === "Admin") return true;
541
535
  if (this.currentUser.storeId === order.storeId) return true;
542
536
  return false;
543
537
  });
544
538
 
545
539
  // ... continue with export
546
- }
540
+ };
547
541
  ```
548
542
 
549
543
  #### Using Custom Pipes for Formatting
@@ -551,33 +545,33 @@ downloadTable = async (arrange: Arrange, conditions: Condition[]) => {
551
545
  Apply Angular pipes to format data in the export:
552
546
 
553
547
  ```typescript
554
- import { DatePipe, CurrencyPipe } from '@angular/common';
548
+ import { DatePipe, CurrencyPipe } from "@angular/common";
555
549
 
556
550
  downloadTable = async (arrange: Arrange, conditions: Condition[]) => {
557
- const rawData = await this.tableService.getItemsData('products', arrange);
558
-
559
- const datePipe = new DatePipe('en-US');
560
- const currencyPipe = new CurrencyPipe('en-US');
561
-
562
- const xlsxData = rawData.map(product => ({
563
- 'Product': product.name,
564
- 'Price': currencyPipe.transform(product.price),
565
- 'Created': datePipe.transform(product.createdAt.toDate(), 'short'),
566
- 'Status': product.active ? 'Active' : 'Inactive'
551
+ const rawData = await this.tableService.getItemsData("products", arrange);
552
+
553
+ const datePipe = new DatePipe("en-US");
554
+ const currencyPipe = new CurrencyPipe("en-US");
555
+
556
+ const xlsxData = rawData.map((product) => ({
557
+ Product: product.name,
558
+ Price: currencyPipe.transform(product.price),
559
+ Created: datePipe.transform(product.createdAt.toDate(), "short"),
560
+ Status: product.active ? "Active" : "Inactive",
567
561
  }));
568
562
 
569
563
  // ... continue with export
570
- }
564
+ };
571
565
  ```
572
566
 
573
567
  #### CSV vs XLSX Format
574
568
 
575
569
  ```typescript
576
570
  // Export as XLSX (default)
577
- XLSX.writeFile(workbook, 'data.xlsx');
571
+ XLSX.writeFile(workbook, "data.xlsx");
578
572
 
579
573
  // Export as CSV
580
- XLSX.writeFile(workbook, 'data.csv', { bookType: 'csv', type: 'binary' });
574
+ XLSX.writeFile(workbook, "data.csv", { bookType: "csv", type: "binary" });
581
575
  ```
582
576
 
583
577
  #### Important Notes
@@ -600,4 +594,4 @@ This project is released under the MIT License. See the [LICENSE](LICENSE) file
600
594
 
601
595
  ## Support the Project
602
596
 
603
- If this library saves you time, please star the repository and share it with your team.
597
+ If this library saves you time, please star the repository and share it with your team.