ngx-st-tables 18.0.19 → 18.0.21

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
@@ -1,153 +1,1240 @@
1
- # NgxStTables
1
+ # Material Table Component - Complete Input/Output Reference
2
2
 
3
- This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.0.
3
+ ## Table of Contents
4
+ - [Overview](#overview)
5
+ - [Basic Inputs](#basic-inputs)
6
+ - [Display & Layout Inputs](#display--layout-inputs)
7
+ - [Data Management Inputs](#data-management-inputs)
8
+ - [Row Selection Inputs](#row-selection-inputs)
9
+ - [Row Editing Inputs](#row-editing-inputs)
10
+ - [Row Actions Inputs](#row-actions-inputs)
11
+ - [Column Configuration](#column-configuration)
12
+ - [Outputs (Events)](#outputs-events)
13
+ - [Usage Examples](#usage-examples)
4
14
 
5
- ## Usage
15
+ ---
6
16
 
7
- ### Immutable Data Pattern
17
+ ## Overview
8
18
 
9
- The table library follows an immutable data pattern where:
10
- - The parent component owns and controls the data
11
- - The table works on a copy of the data
12
- - Changes are communicated back to the parent through events
13
- - The parent decides whether to accept/reject changes
19
+ The `ngx-st-material-table` component is a powerful Angular Material table with features including:
20
+ - Pagination, sorting, and filtering
21
+ - Lazy loading support
22
+ - Row editing (inline editing or auto-save)
23
+ - Row selection (single or multiple)
24
+ - Custom column templates
25
+ - Expandable rows
26
+ - Local storage persistence
27
+ - Create, update, and delete operations
14
28
 
15
- ### Example: Using Add/Edit Row Features
29
+ ---
16
30
 
17
- ```typescript
18
- // Parent Component
19
- @Component({
20
- selector: 'app-example',
21
- template: `
22
- <ngx-st-material-table
23
- [data]="tableData"
24
- [initColumns]="columns"
25
- [allowEditRow]="true"
26
- [createButtonUseAddRow]="true"
27
- (saveNewCreatedRow)="onSaveNewCreatedRow($event)"
28
- (saveNewRow)="onSaveEditedRow($event)"
29
- />
30
- `
31
- })
32
- export class ExampleComponent {
33
- tableData: any[] = [];
34
-
35
- columns: StMaterialTableColumnModel[] = [
36
- { field: 'name', header: 'Name', allowEditColumn: true, editColumnRequired: true },
37
- { field: 'email', header: 'Email', allowEditColumn: true },
38
- ];
31
+ ## Basic Inputs
39
32
 
40
- // Handle new row creation
41
- onSaveNewCreatedRow(row: any) {
42
- // The library generated an ID and validated the row
43
- // Parent decides how to handle it (e.g., API call)
44
- this.apiService.createRow(row).subscribe(response => {
45
- // Update parent's data with server response
46
- this.tableData = [...this.tableData, response];
47
- });
33
+ ### `tableTitle`
34
+ - **Type:** `string`
35
+ - **Default:** `''`
36
+ - **Description:** Title displayed at the top of the table in the caption area.
37
+ - **Example:**
38
+ ```typescript
39
+ tableTitle="Users List"
40
+ ```
41
+
42
+ ### `pageSize`
43
+ - **Type:** `number`
44
+ - **Default:** `10`
45
+ - **Description:** Number of rows to display per page.
46
+ - **Example:**
47
+ ```typescript
48
+ [pageSize]="25"
49
+ ```
50
+
51
+ ### `dataLength`
52
+ - **Type:** `number`
53
+ - **Default:** `0`
54
+ - **Description:** Total number of records (used for lazy loading pagination). Only needed when `lazyLoading` is true.
55
+ - **Example:**
56
+ ```typescript
57
+ [dataLength]="totalRecords"
58
+ ```
59
+
60
+ ### `data`
61
+ - **Type:** `any[]`
62
+ - **Default:** `[]`
63
+ - **Description:** Array of data objects to display in the table. Each object represents one row.
64
+ - **Important:** Uses immutable data pattern. Always pass a new array reference when updating data.
65
+ - **Example:**
66
+ ```typescript
67
+ [data]="users"
68
+ ```
69
+
70
+ ### `initColumns`
71
+ - **Type:** `StMaterialTableColumnModel[]`
72
+ - **Default:** `[]`
73
+ - **Description:** Array of column definitions that configure how each column is displayed and behaves.
74
+ - **See:** [Column Configuration](#column-configuration) section for details.
75
+ - **Example:**
76
+ ```typescript
77
+ [initColumns]="columnDefs"
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Display & Layout Inputs
83
+
84
+ ### `showGlobalSearch`
85
+ - **Type:** `boolean`
86
+ - **Default:** `false`
87
+ - **Description:** Shows a global search input that searches across all visible columns.
88
+ - **Example:**
89
+ ```typescript
90
+ [showGlobalSearch]="true"
91
+ ```
92
+
93
+ ### `allowPickColumns`
94
+ - **Type:** `boolean`
95
+ - **Default:** `false`
96
+ - **Description:** Allows users to show/hide columns via a column picker dialog.
97
+ - **Example:**
98
+ ```typescript
99
+ [allowPickColumns]="true"
100
+ ```
101
+
102
+ ### `allowReorderColumns`
103
+ - **Type:** `boolean`
104
+ - **Default:** `false`
105
+ - **Description:** Allows users to reorder columns by dragging them.
106
+ - **Example:**
107
+ ```typescript
108
+ [allowReorderColumns]="true"
109
+ ```
110
+
111
+ ### `localStorageName`
112
+ - **Type:** `string`
113
+ - **Default:** `''`
114
+ - **Description:** Key name for storing table state (pagination, sorting, filters, column order) in localStorage. If empty, state is not persisted.
115
+ - **Example:**
116
+ ```typescript
117
+ localStorageName="users-table-state"
118
+ ```
119
+
120
+ ### `isLoading`
121
+ - **Type:** `boolean`
122
+ - **Default:** `false`
123
+ - **Description:** Shows a loading spinner overlay on the table.
124
+ - **Example:**
125
+ ```typescript
126
+ [isLoading]="loading"
127
+ ```
128
+
129
+ ### `extraCustomFilter`
130
+ - **Type:** `TemplateRef<any>`
131
+ - **Default:** `undefined`
132
+ - **Description:** Custom template for additional filter controls displayed in the table caption area.
133
+ - **Example:**
134
+ ```html
135
+ <ng-template #customFilters>
136
+ <mat-form-field>
137
+ <mat-select placeholder="Status">
138
+ <mat-option value="active">Active</mat-option>
139
+ <mat-option value="inactive">Inactive</mat-option>
140
+ </mat-select>
141
+ </mat-form-field>
142
+ </ng-template>
143
+
144
+ [extraCustomFilter]="customFilters"
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Data Management Inputs
150
+
151
+ ### `lazyLoading`
152
+ - **Type:** `boolean`
153
+ - **Default:** `false`
154
+ - **Description:** Enables server-side pagination, sorting, and filtering. When true, table emits `loadData` events instead of handling data locally.
155
+ - **Required with:** `dataLength` input must be provided
156
+ - **Example:**
157
+ ```typescript
158
+ [lazyLoading]="true"
159
+ [dataLength]="totalRecords"
160
+ (loadData)="onLoadData($event)"
161
+ ```
162
+
163
+ ### `setNewDataWithoutRefresh`
164
+ - **Type:** `boolean`
165
+ - **Default:** `false`
166
+ - **Description:** When true and data array length hasn't changed, updates existing row objects in place without recreating table rows. This preserves focus state during editing and prevents UI flickering.
167
+ - **Use case:** Ideal for real-time updates or auto-save scenarios where you frequently update data.
168
+ - **Example:**
169
+ ```typescript
170
+ [setNewDataWithoutRefresh]="true"
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Row Selection Inputs
176
+
177
+ ### `allowSelectRow`
178
+ - **Type:** `boolean`
179
+ - **Default:** `false`
180
+ - **Description:** Enables row selection with checkboxes. Adds a selection column to the left of the table.
181
+ - **Example:**
182
+ ```typescript
183
+ [allowSelectRow]="true"
184
+ (selectRowChange)="onSelectionChange($event)"
185
+ ```
186
+
187
+ ### `selectionFieldLabel`
188
+ - **Type:** `string`
189
+ - **Default:** `''`
190
+ - **Description:** Property name from the row object to use as the display label for selected rows (shown in chips).
191
+ - **Example:**
192
+ ```typescript
193
+ selectionFieldLabel="name"
194
+ ```
195
+
196
+ ### `selectRowOnlyOne`
197
+ - **Type:** `boolean`
198
+ - **Default:** `false`
199
+ - **Description:** When true, only one row can be selected at a time (radio button behavior instead of checkboxes).
200
+ - **Example:**
201
+ ```typescript
202
+ [selectRowOnlyOne]="true"
203
+ ```
204
+
205
+ ### `selectRowValueDisplay`
206
+ - **Type:** `(row: any) => string`
207
+ - **Default:** `undefined`
208
+ - **Description:** Custom formatter function to generate the display value for selected rows. Takes precedence over `selectionFieldLabel`.
209
+ - **Use case:** When you need to display multiple fields or apply custom formatting.
210
+ - **Example:**
211
+ ```typescript
212
+ [selectRowValueDisplay]="formatSelectedRow"
213
+
214
+ formatSelectedRow(row: any): string {
215
+ return `${row.firstName} ${row.lastName} (${row.email})`;
216
+ }
217
+ ```
218
+
219
+ ### `initSelectedRow`
220
+ - **Type:** `any` or `any[]`
221
+ - **Default:** `undefined`
222
+ - **Description:** Pre-selected row(s) when the table initializes.
223
+ - **Example:**
224
+ ```typescript
225
+ [initSelectedRow]="preSelectedUsers"
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Row Editing Inputs
231
+
232
+ ### `allowEditRow`
233
+ - **Type:** `boolean`
234
+ - **Default:** `false`
235
+ - **Description:** Enables inline row editing. Adds edit/delete action buttons to each row (unless `autoSaveOnChange` is true).
236
+ - **Note:** Columns must have `allowEditColumn: true` to be editable.
237
+ - **Example:**
238
+ ```typescript
239
+ [allowEditRow]="true"
240
+ (saveEditedRow)="onRowSaved($event)"
241
+ ```
242
+
243
+ ### `allowEditInEditRow`
244
+ - **Type:** `boolean`
245
+ - **Default:** `true`
246
+ - **Description:** Shows the edit button in the actions column. Set to false to hide it while still allowing editing functionality.
247
+ - **Example:**
248
+ ```typescript
249
+ [allowEditInEditRow]="false"
250
+ ```
251
+
252
+ ### `allowDeleteInEditRow`
253
+ - **Type:** `boolean`
254
+ - **Default:** `true`
255
+ - **Description:** Shows the delete button in the actions column.
256
+ - **Example:**
257
+ ```typescript
258
+ [allowDeleteInEditRow]="false"
259
+ ```
260
+
261
+ ### `showEditAllRows`
262
+ - **Type:** `boolean`
263
+ - **Default:** `false`
264
+ - **Description:** Shows a button in the table caption that toggles edit mode for all rows simultaneously.
265
+ - **Example:**
266
+ ```typescript
267
+ [showEditAllRows]="true"
268
+ ```
269
+
270
+ ### `autoSaveOnChange`
271
+ - **Type:** `boolean`
272
+ - **Default:** `false`
273
+ - **Description:** When true, field changes are saved immediately without requiring save/cancel buttons. Perfect for quantity inputs, toggles, or selection tables where instant updates are needed.
274
+ - **Behavior:**
275
+ - Removes save/cancel buttons from the table
276
+ - Emits `fieldValueChanged` event on every field change
277
+ - Parent should update their data source immediately
278
+ - **Example:**
279
+ ```typescript
280
+ [autoSaveOnChange]="true"
281
+ (fieldValueChanged)="onFieldChanged($event)"
282
+
283
+ onFieldChanged(event: { row: any; field: string; value: any; index: number }) {
284
+ // Update your data source
285
+ this.users[event.index][event.field] = event.value;
286
+ // Optionally call API to persist
287
+ this.updateUser(event.row);
288
+ }
289
+ ```
290
+
291
+ ### `canEditRowValidator`
292
+ - **Type:** `(row: any) => boolean`
293
+ - **Default:** `() => true`
294
+ - **Description:** Function to determine if a specific row can be edited. Return false to disable editing for that row.
295
+ - **Example:**
296
+ ```typescript
297
+ [canEditRowValidator]="canEditUser"
298
+
299
+ canEditUser(row: any): boolean {
300
+ return row.status !== 'archived' && row.isEditable;
301
+ }
302
+ ```
303
+
304
+ ### `canDeleteRowValidator`
305
+ - **Type:** `(row: any) => boolean`
306
+ - **Default:** `() => true`
307
+ - **Description:** Function to determine if a specific row can be deleted. Return false to disable delete button for that row.
308
+ - **Example:**
309
+ ```typescript
310
+ [canDeleteRowValidator]="canDeleteUser"
311
+
312
+ canDeleteUser(row: any): boolean {
313
+ return row.status !== 'system' && !row.hasRelatedRecords;
314
+ }
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Row Actions Inputs
320
+
321
+ ### `rowClickAction`
322
+ - **Type:** `(row: any) => void`
323
+ - **Default:** `undefined`
324
+ - **Description:** Function called when a row is clicked (only if `allowSelectRow` and `allowExtendRow` are false).
325
+ - **Example:**
326
+ ```typescript
327
+ [rowClickAction]="onRowClick"
328
+
329
+ onRowClick(row: any): void {
330
+ this.router.navigate(['/users', row.id]);
331
+ }
332
+ ```
333
+
334
+ ### `allowCreateRow`
335
+ - **Type:** `boolean`
336
+ - **Default:** `false`
337
+ - **Description:** Shows an "Add New Row" button below the table that adds a new editable row.
338
+ - **Example:**
339
+ ```typescript
340
+ [allowCreateRow]="true"
341
+ (saveCreatedRow)="onRowCreated($event)"
342
+ ```
343
+
344
+ ### `showCreateButton`
345
+ - **Type:** `boolean`
346
+ - **Default:** `false`
347
+ - **Description:** Shows a custom create button in the table caption (separate from `allowCreateRow`).
348
+ - **Example:**
349
+ ```typescript
350
+ [showCreateButton]="true"
351
+ [createButtonLabel]="'Add User'"
352
+ [createButtonAction]="openCreateDialog"
353
+ ```
354
+
355
+ ### `createButtonLabel`
356
+ - **Type:** `string`
357
+ - **Default:** `'Create'`
358
+ - **Description:** Label text for the create button (when `showCreateButton` is true).
359
+ - **Example:**
360
+ ```typescript
361
+ createButtonLabel="Add New User"
362
+ ```
363
+
364
+ ### `createButtonAction`
365
+ - **Type:** `() => void`
366
+ - **Default:** `() => {}`
367
+ - **Description:** Function called when the create button is clicked.
368
+ - **Example:**
369
+ ```typescript
370
+ [createButtonAction]="openCreateDialog"
371
+
372
+ openCreateDialog(): void {
373
+ // Open a dialog or navigate to create page
48
374
  }
375
+ ```
376
+
377
+ ### `disableCreateButton`
378
+ - **Type:** `boolean`
379
+ - **Default:** `false`
380
+ - **Description:** Disables the create button.
381
+ - **Example:**
382
+ ```typescript
383
+ [disableCreateButton]="!hasPermission"
384
+ ```
385
+
386
+ ---
49
387
 
50
- // Handle row editing
51
- onSaveEditedRow(row: any) {
52
- this.apiService.updateRow(row).subscribe(response => {
53
- const index = this.tableData.findIndex(r => r.id === row.id);
54
- if (index !== -1) {
55
- this.tableData[index] = response;
56
- this.tableData = [...this.tableData];
388
+ ## Row Expansion Inputs
389
+
390
+ ### `allowExtendRow`
391
+ - **Type:** `boolean`
392
+ - **Default:** `false`
393
+ - **Description:** Enables expandable rows with a toggle button. Clicking a row expands/collapses its detail view.
394
+ - **Required with:** `extendedRowTemplate` must be provided.
395
+ - **Example:**
396
+ ```typescript
397
+ [allowExtendRow]="true"
398
+ [extendedRowTemplate]="detailTemplate"
399
+ ```
400
+
401
+ ### `extendedRowTemplate`
402
+ - **Type:** `TemplateRef<{ data: any }>`
403
+ - **Default:** `undefined`
404
+ - **Description:** Template for the expanded row content. Receives the row data via context.
405
+ - **Example:**
406
+ ```html
407
+ <ng-template #detailTemplate let-data="data">
408
+ <div class="row-details">
409
+ <h3>User Details</h3>
410
+ <p><strong>Email:</strong> {{ data.email }}</p>
411
+ <p><strong>Phone:</strong> {{ data.phone }}</p>
412
+ <p><strong>Address:</strong> {{ data.address }}</p>
413
+ </div>
414
+ </ng-template>
415
+
416
+ [extendedRowTemplate]="detailTemplate"
417
+ ```
418
+
419
+ ---
420
+
421
+ ## Column Configuration
422
+
423
+ Columns are configured via the `initColumns` input using the `StMaterialTableColumnModel` interface.
424
+
425
+ ### Column Model Properties
426
+
427
+ #### Basic Properties
428
+
429
+ ##### `field`
430
+ - **Type:** `string`
431
+ - **Required:** Yes
432
+ - **Description:** Property name from the data object to display in this column.
433
+ - **Example:** `field: 'firstName'`
434
+
435
+ ##### `header`
436
+ - **Type:** `string`
437
+ - **Required:** Yes
438
+ - **Description:** Column header text displayed in the table header.
439
+ - **Example:** `header: 'First Name'`
440
+
441
+ ##### `type`
442
+ - **Type:** `StMaterialColumnType`
443
+ - **Options:** `'string'` | `'number'` | `'boolean'` | `'date'` | `'custom-template'` | `'actions'`
444
+ - **Default:** `'string'`
445
+ - **Description:** Data type of the column, affects display formatting and default filter/edit types.
446
+ - **Example:** `type: 'date'`
447
+
448
+ ##### `width`
449
+ - **Type:** `string`
450
+ - **Default:** Auto
451
+ - **Description:** CSS width value for the column.
452
+ - **Example:** `width: '150px'` or `width: '20%'`
453
+
454
+ ##### `flexRight`
455
+ - **Type:** `boolean`
456
+ - **Default:** `false`
457
+ - **Description:** Aligns column content to the right.
458
+ - **Example:** `flexRight: true`
459
+
460
+ #### Sorting & Filtering
461
+
462
+ ##### `sort`
463
+ - **Type:** `boolean`
464
+ - **Default:** `true`
465
+ - **Description:** Enables sorting for this column.
466
+ - **Example:** `sort: false`
467
+
468
+ ##### `filter`
469
+ - **Type:** `boolean`
470
+ - **Default:** `true`
471
+ - **Description:** Enables filtering for this column.
472
+ - **Example:** `filter: true`
473
+
474
+ ##### `filterType`
475
+ - **Type:** `StMaterialColumnFilterType`
476
+ - **Options:** `'string'` | `'number'` | `'boolean'` | `'date'` | `'custom'`
477
+ - **Default:** Auto-detected from `type`
478
+ - **Description:** Type of filter input to show for this column.
479
+ - **Example:** `filterType: 'date'`
480
+
481
+ ##### `customFilterOptions`
482
+ - **Type:** `{ value: string; label: string }[]`
483
+ - **Default:** `undefined`
484
+ - **Description:** Options for a dropdown filter (when filterType is 'custom').
485
+ - **Example:**
486
+ ```typescript
487
+ customFilterOptions: [
488
+ { value: 'active', label: 'Active' },
489
+ { value: 'inactive', label: 'Inactive' }
490
+ ]
491
+ ```
492
+
493
+ #### Display Customization
494
+
495
+ ##### `customTemplate`
496
+ - **Type:** `TemplateRef<any>`
497
+ - **Default:** `undefined`
498
+ - **Description:** Custom template for rendering cell content (use with `type: 'custom-template'`).
499
+ - **Example:**
500
+ ```html
501
+ <ng-template #statusTemplate let-row="row">
502
+ <span [class]="'status-' + row.status">{{ row.status }}</span>
503
+ </ng-template>
504
+
505
+ {
506
+ field: 'status',
507
+ header: 'Status',
508
+ type: 'custom-template',
509
+ customTemplate: statusTemplate
510
+ }
511
+ ```
512
+
513
+ ##### `customValueDisplay`
514
+ - **Type:** `(row: any) => string`
515
+ - **Default:** `undefined`
516
+ - **Description:** Function to transform the cell value for display.
517
+ - **Example:**
518
+ ```typescript
519
+ {
520
+ field: 'price',
521
+ header: 'Price',
522
+ customValueDisplay: (row) => `$${row.price.toFixed(2)}`
523
+ }
524
+ ```
525
+
526
+ ##### `translateValue`
527
+ - **Type:** `{ [value: string]: string }`
528
+ - **Default:** `undefined`
529
+ - **Description:** Map of values to translated/display values.
530
+ - **Example:**
531
+ ```typescript
532
+ {
533
+ field: 'status',
534
+ header: 'Status',
535
+ translateValue: {
536
+ 'A': 'Active',
537
+ 'I': 'Inactive',
538
+ 'P': 'Pending'
539
+ }
540
+ }
541
+ ```
542
+
543
+ #### Row Editing Configuration
544
+
545
+ ##### `allowEditColumn`
546
+ - **Type:** `boolean`
547
+ - **Default:** `false`
548
+ - **Description:** Makes this column editable when row is in edit mode.
549
+ - **Example:** `allowEditColumn: true`
550
+
551
+ ##### `rowEditType`
552
+ - **Type:** `StMaterialRowEditType`
553
+ - **Options:** `'string'` | `'number'` | `'boolean'` | `'date'` | `'custom'` | `'custom-dynamic-select'`
554
+ - **Default:** Auto-detected from `type`
555
+ - **Description:** Type of input to show when editing this column.
556
+ - **Example:** `rowEditType: 'number'`
557
+
558
+ ##### `customRowEditOptions`
559
+ - **Type:** `{ value: any; label: string }[]`
560
+ - **Default:** `undefined`
561
+ - **Description:** Static options for a dropdown editor (when rowEditType is 'custom').
562
+ - **Example:**
563
+ ```typescript
564
+ customRowEditOptions: [
565
+ { value: 'admin', label: 'Administrator' },
566
+ { value: 'user', label: 'Regular User' },
567
+ { value: 'guest', label: 'Guest' }
568
+ ]
569
+ ```
570
+
571
+ ##### `dynamicRowEditOptions`
572
+ - **Type:** `(row: any) => { value: any; label: string }[]`
573
+ - **Default:** `undefined`
574
+ - **Description:** Dynamic function to generate dropdown options based on the current row (when rowEditType is 'custom-dynamic-select').
575
+ - **Use case:** When options depend on other field values in the row.
576
+ - **Example:**
577
+ ```typescript
578
+ dynamicRowEditOptions: (row) => {
579
+ if (row.country === 'USA') {
580
+ return [
581
+ { value: 'NY', label: 'New York' },
582
+ { value: 'CA', label: 'California' }
583
+ ];
584
+ } else {
585
+ return [
586
+ { value: 'LON', label: 'London' },
587
+ { value: 'MAN', label: 'Manchester' }
588
+ ];
589
+ }
590
+ }
591
+ ```
592
+
593
+ ##### `editColumnRequired`
594
+ - **Type:** `boolean`
595
+ - **Default:** `false`
596
+ - **Description:** Makes this column required when editing. Shows error if empty on save.
597
+ - **Example:** `editColumnRequired: true`
598
+
599
+ ##### `disableEdit`
600
+ - **Type:** `(row: any) => boolean`
601
+ - **Default:** `undefined`
602
+ - **Description:** Function to determine if this specific column should be disabled for editing in a particular row.
603
+ - **Example:**
604
+ ```typescript
605
+ disableEdit: (row) => row.status === 'locked'
606
+ ```
607
+
608
+ ##### `customEditRowValidator`
609
+ - **Type:** `(oldValue: any, newValue: any, row: any) => { isValid: boolean; errorMessage: string }`
610
+ - **Default:** `undefined`
611
+ - **Description:** Custom validation function for this column during editing.
612
+ - **Example:**
613
+ ```typescript
614
+ customEditRowValidator: (oldValue, newValue, row) => {
615
+ if (newValue < 0) {
616
+ return { isValid: false, errorMessage: 'Value cannot be negative' };
617
+ }
618
+ if (newValue > row.maxValue) {
619
+ return { isValid: false, errorMessage: 'Value exceeds maximum' };
620
+ }
621
+ return { isValid: true, errorMessage: '' };
622
+ }
623
+ ```
624
+
625
+ #### Actions Column Configuration
626
+
627
+ ##### `actions`
628
+ - **Type:** `StMaterialTableActionColumnModel[]`
629
+ - **Default:** `undefined`
630
+ - **Description:** Array of action buttons to show in this column (use with `type: 'actions'`).
631
+ - **Example:**
632
+ ```typescript
633
+ {
634
+ field: 'actions',
635
+ header: 'Actions',
636
+ type: 'actions',
637
+ sort: false,
638
+ filter: false,
639
+ actions: [
640
+ {
641
+ iconName: 'edit',
642
+ tooltipName: 'Edit User',
643
+ iconColor: 'primary',
644
+ action: (row) => this.editUser(row),
645
+ show: (row) => row.canEdit
646
+ },
647
+ {
648
+ iconName: 'delete',
649
+ tooltipName: 'Delete User',
650
+ iconColor: 'warn',
651
+ action: (row) => this.deleteUser(row),
652
+ show: (row) => row.canDelete
57
653
  }
654
+ ]
655
+ }
656
+ ```
657
+
658
+ ##### `actionsInMenu`
659
+ - **Type:** `boolean`
660
+ - **Default:** `false`
661
+ - **Description:** Shows actions in a dropdown menu instead of as individual buttons.
662
+ - **Example:** `actionsInMenu: true`
663
+
664
+ #### Action Button Model
665
+
666
+ Each action in the `actions` array has the following properties:
667
+
668
+ - **`iconName`** (string, required): Material icon name
669
+ - **`tooltipName`** (string, optional): Tooltip text
670
+ - **`iconColor`** ('primary' | 'warn' | 'accent', optional): Icon color
671
+ - **`action`** ((row: any, index?: number) => void, optional): Function called when clicked
672
+ - **`show`** ((row: any) => boolean, optional): Function to conditionally show/hide the action
673
+ - **`url`** (string[], optional): Router navigation path (alternative to `action`)
674
+
675
+ #### Other Properties
676
+
677
+ ##### `notShowInColumnPick`
678
+ - **Type:** `boolean`
679
+ - **Default:** `false`
680
+ - **Description:** Hides this column from the column picker dialog.
681
+ - **Example:** `notShowInColumnPick: true`
682
+
683
+ ##### `selectColumnLabel`
684
+ - **Type:** `string`
685
+ - **Default:** `undefined`
686
+ - **Description:** Used for special columns like selection, editing, extending. Sets the aria-label.
687
+
688
+ ---
689
+
690
+ ## Outputs (Events)
691
+
692
+ ### `loadData`
693
+ - **Type:** `StMaterialTableLoadData`
694
+ - **When emitted:** When lazy loading is enabled and data needs to be loaded (pagination, sorting, filtering changes).
695
+ - **Payload:**
696
+ ```typescript
697
+ {
698
+ first: number; // Starting index
699
+ rows: number; // Number of rows to load
700
+ globalFilter: string; // Global search text
701
+ globalFilterColumns: string[]; // Columns to search
702
+ sortField: string; // Field to sort by
703
+ sortOrder: SortDirection; // 'asc' | 'desc'
704
+ filters: { [key: string]: StMaterialTableFilter }; // Column filters
705
+ }
706
+ ```
707
+ - **Example:**
708
+ ```typescript
709
+ (loadData)="onLoadData($event)"
710
+
711
+ onLoadData(event: StMaterialTableLoadData): void {
712
+ this.loading = true;
713
+ this.userService.getUsers(event).subscribe(response => {
714
+ this.users = response.data;
715
+ this.totalRecords = response.total;
716
+ this.loading = false;
58
717
  });
59
718
  }
719
+ ```
720
+
721
+ ### `saveEditedRow`
722
+ - **Type:** `{ row: any; index: number }`
723
+ - **When emitted:** When user saves an edited existing row.
724
+ - **Payload:** The modified row object and its index.
725
+ - **Example:**
726
+ ```typescript
727
+ (saveEditedRow)="onRowEdited($event)"
728
+
729
+ onRowEdited(event: { row: any; index: number }): void {
730
+ this.userService.updateUser(event.row).subscribe(
731
+ () => {
732
+ // Update your data array
733
+ this.users[event.index] = event.row;
734
+ this.snackbar.success('User updated successfully');
735
+ },
736
+ error => {
737
+ this.snackbar.error('Failed to update user');
738
+ }
739
+ );
740
+ }
741
+ ```
742
+
743
+ ### `saveCreatedRow`
744
+ - **Type:** `any`
745
+ - **When emitted:** When user saves a newly created row (via `allowCreateRow`).
746
+ - **Payload:** The new row object.
747
+ - **Example:**
748
+ ```typescript
749
+ (saveCreatedRow)="onRowCreated($event)"
750
+
751
+ onRowCreated(row: any): void {
752
+ this.userService.createUser(row).subscribe(
753
+ (createdUser) => {
754
+ // Add to your data array
755
+ this.users = [...this.users, createdUser];
756
+ this.snackbar.success('User created successfully');
757
+ },
758
+ error => {
759
+ this.snackbar.error('Failed to create user');
760
+ }
761
+ );
762
+ }
763
+ ```
764
+
765
+ ### `rowDeleted`
766
+ - **Type:** `{ row: any; index: number }`
767
+ - **When emitted:** When user deletes a row.
768
+ - **Payload:** The deleted row object and its index.
769
+ - **Example:**
770
+ ```typescript
771
+ (rowDeleted)="onRowDeleted($event)"
772
+
773
+ onRowDeleted(event: { row: any; index: number }): void {
774
+ this.userService.deleteUser(event.row.id).subscribe(
775
+ () => {
776
+ // Remove from your data array
777
+ this.users = this.users.filter(u => u.id !== event.row.id);
778
+ this.snackbar.success('User deleted successfully');
779
+ },
780
+ error => {
781
+ this.snackbar.error('Failed to delete user');
782
+ }
783
+ );
784
+ }
785
+ ```
786
+
787
+ ### `selectRowChange`
788
+ - **Type:** `any[]`
789
+ - **When emitted:** When row selection changes.
790
+ - **Payload:** Array of selected row objects.
791
+ - **Example:**
792
+ ```typescript
793
+ (selectRowChange)="onSelectionChange($event)"
794
+
795
+ onSelectionChange(selectedRows: any[]): void {
796
+ this.selectedUsers = selectedRows;
797
+ console.log(`${selectedRows.length} users selected`);
798
+ }
799
+ ```
800
+
801
+ ### `fieldValueChanged`
802
+ - **Type:** `{ row: any; field: string; value: any; index: number }`
803
+ - **When emitted:** When `autoSaveOnChange` is enabled and a field value changes.
804
+ - **Payload:** The row, field name, new value, and row index.
805
+ - **Important:** You must update your data source immediately when receiving this event.
806
+ - **Example:**
807
+ ```typescript
808
+ (fieldValueChanged)="onFieldChanged($event)"
809
+
810
+ onFieldChanged(event: { row: any; field: string; value: any; index: number }): void {
811
+ // Update local data
812
+ this.users[event.index][event.field] = event.value;
813
+
814
+ // Optionally persist to server
815
+ this.userService.updateUser(event.row).subscribe();
816
+ }
817
+ ```
818
+
819
+ ---
820
+
821
+ ## Usage Examples
822
+
823
+ ### Example 1: Basic Table with Sorting and Filtering
824
+
825
+ ```typescript
826
+ // Component
827
+ columns: StMaterialTableColumnModel[] = [
828
+ { field: 'id', header: 'ID', width: '80px' },
829
+ { field: 'firstName', header: 'First Name', filter: true },
830
+ { field: 'lastName', header: 'Last Name', filter: true },
831
+ { field: 'email', header: 'Email', filter: true },
832
+ { field: 'age', header: 'Age', type: 'number' }
833
+ ];
834
+
835
+ users: any[] = [
836
+ { id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com', age: 30 },
837
+ { id: 2, firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com', age: 25 }
838
+ ];
839
+ ```
840
+
841
+ ```html
842
+ <!-- Template -->
843
+ <ngx-st-material-table
844
+ tableTitle="Users"
845
+ [pageSize]="10"
846
+ [data]="users"
847
+ [initColumns]="columns"
848
+ [showGlobalSearch]="true"
849
+ [allowPickColumns]="true"
850
+ localStorageName="users-table">
851
+ </ngx-st-material-table>
852
+ ```
853
+
854
+ ### Example 2: Lazy Loading Table
855
+
856
+ ```typescript
857
+ // Component
858
+ columns: StMaterialTableColumnModel[] = [
859
+ { field: 'name', header: 'Name', filter: true },
860
+ { field: 'status', header: 'Status', filter: true, filterType: 'custom',
861
+ customFilterOptions: [
862
+ { value: 'active', label: 'Active' },
863
+ { value: 'inactive', label: 'Inactive' }
864
+ ]
865
+ }
866
+ ];
867
+
868
+ users: any[] = [];
869
+ totalRecords = 0;
870
+ loading = false;
871
+
872
+ onLoadData(event: StMaterialTableLoadData): void {
873
+ this.loading = true;
874
+ this.userService.getUsers(event).subscribe(response => {
875
+ this.users = response.data;
876
+ this.totalRecords = response.total;
877
+ this.loading = false;
878
+ });
60
879
  }
61
880
  ```
62
881
 
63
- ### Benefits
64
- - **Single source of truth**: Parent's data is never mutated
65
- - **No ID conflicts**: IDs are generated once in the library
66
- - **Clear responsibility**: Library manages UI state, parent manages data
67
- - **Flexibility**: Parent can reject/modify changes before updating
882
+ ```html
883
+ <!-- Template -->
884
+ <ngx-st-material-table
885
+ [lazyLoading]="true"
886
+ [isLoading]="loading"
887
+ [dataLength]="totalRecords"
888
+ [data]="users"
889
+ [initColumns]="columns"
890
+ (loadData)="onLoadData($event)">
891
+ </ngx-st-material-table>
892
+ ```
893
+
894
+ ### Example 3: Editable Table with Validation
895
+
896
+ ```typescript
897
+ // Component
898
+ columns: StMaterialTableColumnModel[] = [
899
+ {
900
+ field: 'name',
901
+ header: 'Name',
902
+ allowEditColumn: true,
903
+ editColumnRequired: true
904
+ },
905
+ {
906
+ field: 'quantity',
907
+ header: 'Quantity',
908
+ type: 'number',
909
+ allowEditColumn: true,
910
+ rowEditType: 'number',
911
+ editColumnRequired: true,
912
+ customEditRowValidator: (oldValue, newValue, row) => {
913
+ if (newValue < 0) {
914
+ return { isValid: false, errorMessage: 'Quantity cannot be negative' };
915
+ }
916
+ if (newValue > 100) {
917
+ return { isValid: false, errorMessage: 'Quantity cannot exceed 100' };
918
+ }
919
+ return { isValid: true, errorMessage: '' };
920
+ }
921
+ },
922
+ {
923
+ field: 'status',
924
+ header: 'Status',
925
+ allowEditColumn: true,
926
+ rowEditType: 'custom',
927
+ customRowEditOptions: [
928
+ { value: 'draft', label: 'Draft' },
929
+ { value: 'published', label: 'Published' }
930
+ ]
931
+ }
932
+ ];
933
+
934
+ onRowEdited(event: { row: any; index: number }): void {
935
+ this.updateItem(event.row);
936
+ }
68
937
 
69
- ### Auto-Save Mode (No Save/Cancel Buttons)
938
+ canEditItem(row: any): boolean {
939
+ return row.status !== 'archived';
940
+ }
941
+ ```
70
942
 
71
- For tables where you want immediate updates without save/cancel buttons (e.g., quantity inputs in selection tables):
943
+ ```html
944
+ <!-- Template -->
945
+ <ngx-st-material-table
946
+ [data]="items"
947
+ [initColumns]="columns"
948
+ [allowEditRow]="true"
949
+ [allowCreateRow]="true"
950
+ [canEditRowValidator]="canEditItem"
951
+ (saveEditedRow)="onRowEdited($event)"
952
+ (saveCreatedRow)="onRowCreated($event)"
953
+ (rowDeleted)="onRowDeleted($event)">
954
+ </ngx-st-material-table>
955
+ ```
956
+
957
+ ### Example 4: Auto-Save Table (Instant Updates)
72
958
 
73
959
  ```typescript
74
- // Parent Component
75
- @Component({
76
- selector: 'app-selection-table',
77
- template: `
78
- <ngx-st-material-table
79
- [data]="tableData"
80
- [initColumns]="columns"
81
- [allowEditRow]="true"
82
- [allowSelectRow]="true"
83
- [autoSaveOnChange]="true"
84
- (fieldValueChanged)="onFieldValueChanged($event)"
85
- (selectRowChange)="onSelectionChanged($event)"
86
- />
87
- `
88
- })
89
- export class SelectionTableComponent {
90
- tableData: any[] = [
91
- { id: 1, name: 'Product A', qty: 0 },
92
- { id: 2, name: 'Product B', qty: 0 },
93
- ];
960
+ // Component
961
+ columns: StMaterialTableColumnModel[] = [
962
+ { field: 'product', header: 'Product' },
963
+ {
964
+ field: 'quantity',
965
+ header: 'Quantity',
966
+ type: 'number',
967
+ allowEditColumn: true,
968
+ rowEditType: 'number'
969
+ },
970
+ {
971
+ field: 'active',
972
+ header: 'Active',
973
+ type: 'boolean',
974
+ allowEditColumn: true
975
+ }
976
+ ];
977
+
978
+ onFieldChanged(event: { row: any; field: string; value: any; index: number }): void {
979
+ // Update local data immediately
980
+ this.items[event.index][event.field] = event.value;
94
981
 
95
- columns: StMaterialTableColumnModel[] = [
96
- { field: 'name', header: 'Name', type: 'string' },
982
+ // Persist to server
983
+ this.itemService.updateItem(event.row).subscribe();
984
+ }
985
+ ```
986
+
987
+ ```html
988
+ <!-- Template -->
989
+ <ngx-st-material-table
990
+ [data]="items"
991
+ [initColumns]="columns"
992
+ [allowEditRow]="true"
993
+ [autoSaveOnChange]="true"
994
+ [setNewDataWithoutRefresh]="true"
995
+ (fieldValueChanged)="onFieldChanged($event)">
996
+ </ngx-st-material-table>
997
+ ```
998
+
999
+ ### Example 5: Selection Table
1000
+
1001
+ ```typescript
1002
+ // Component
1003
+ columns: StMaterialTableColumnModel[] = [
1004
+ { field: 'id', header: 'ID' },
1005
+ { field: 'name', header: 'Name' },
1006
+ { field: 'email', header: 'Email' }
1007
+ ];
1008
+
1009
+ selectedUsers: any[] = [];
1010
+
1011
+ onSelectionChange(selected: any[]): void {
1012
+ this.selectedUsers = selected;
1013
+ }
1014
+
1015
+ formatSelectedUser(row: any): string {
1016
+ return `${row.name} (${row.email})`;
1017
+ }
1018
+ ```
1019
+
1020
+ ```html
1021
+ <!-- Template -->
1022
+ <ngx-st-material-table
1023
+ [data]="users"
1024
+ [initColumns]="columns"
1025
+ [allowSelectRow]="true"
1026
+ selectionFieldLabel="name"
1027
+ [selectRowValueDisplay]="formatSelectedUser"
1028
+ (selectRowChange)="onSelectionChange($event)">
1029
+ </ngx-st-material-table>
1030
+ ```
1031
+
1032
+ ### Example 6: Expandable Rows
1033
+
1034
+ ```html
1035
+ <!-- Template -->
1036
+ <ng-template #detailTemplate let-data="data">
1037
+ <div class="row-detail">
1038
+ <h4>Additional Details</h4>
1039
+ <p><strong>Address:</strong> {{ data.address }}</p>
1040
+ <p><strong>Phone:</strong> {{ data.phone }}</p>
1041
+ <p><strong>Notes:</strong> {{ data.notes }}</p>
1042
+ </div>
1043
+ </ng-template>
1044
+
1045
+ <ngx-st-material-table
1046
+ [data]="users"
1047
+ [initColumns]="columns"
1048
+ [allowExtendRow]="true"
1049
+ [extendedRowTemplate]="detailTemplate">
1050
+ </ngx-st-material-table>
1051
+ ```
1052
+
1053
+ ### Example 7: Custom Column Template
1054
+
1055
+ ```html
1056
+ <!-- Template -->
1057
+ <ng-template #statusBadgeTemplate let-row="row">
1058
+ <span class="badge" [ngClass]="{
1059
+ 'badge-success': row.status === 'active',
1060
+ 'badge-danger': row.status === 'inactive',
1061
+ 'badge-warning': row.status === 'pending'
1062
+ }">
1063
+ {{ row.status | uppercase }}
1064
+ </span>
1065
+ </ng-template>
1066
+ ```
1067
+
1068
+ ```typescript
1069
+ // Component
1070
+ @ViewChild('statusBadgeTemplate') statusBadgeTemplate!: TemplateRef<any>;
1071
+
1072
+ ngAfterViewInit() {
1073
+ this.columns = [
1074
+ { field: 'name', header: 'Name' },
97
1075
  {
98
- field: 'qty',
99
- header: 'Quantity',
100
- type: 'number',
101
- allowEditColumn: true // Field will be editable without save buttons
102
- },
1076
+ field: 'status',
1077
+ header: 'Status',
1078
+ type: 'custom-template',
1079
+ customTemplate: this.statusBadgeTemplate
1080
+ }
103
1081
  ];
1082
+ }
1083
+ ```
104
1084
 
105
- // Handle immediate field changes
106
- onFieldValueChanged(event: { row: any; field: string; value: any }) {
107
- const index = this.tableData.findIndex(r => r.id === event.row.id);
108
- if (index !== -1) {
109
- this.tableData[index][event.field] = event.value;
110
-
111
- // Optional: Send to API immediately or batch updates
112
- console.log('Updated:', event.row.name, event.field, event.value);
113
- }
114
- }
1085
+ ### Example 8: Actions Column
115
1086
 
116
- onSelectionChanged(selectedRows: any[]) {
117
- console.log('Selected rows with quantities:', selectedRows);
1087
+ ```typescript
1088
+ // Component
1089
+ columns: StMaterialTableColumnModel[] = [
1090
+ { field: 'name', header: 'Name' },
1091
+ { field: 'email', header: 'Email' },
1092
+ {
1093
+ field: 'actions',
1094
+ header: 'Actions',
1095
+ type: 'actions',
1096
+ sort: false,
1097
+ filter: false,
1098
+ width: '120px',
1099
+ actions: [
1100
+ {
1101
+ iconName: 'visibility',
1102
+ tooltipName: 'View Details',
1103
+ action: (row) => this.viewUser(row)
1104
+ },
1105
+ {
1106
+ iconName: 'edit',
1107
+ tooltipName: 'Edit User',
1108
+ iconColor: 'primary',
1109
+ action: (row) => this.editUser(row),
1110
+ show: (row) => row.canEdit
1111
+ },
1112
+ {
1113
+ iconName: 'delete',
1114
+ tooltipName: 'Delete User',
1115
+ iconColor: 'warn',
1116
+ action: (row, index) => this.deleteUser(row, index),
1117
+ show: (row) => row.canDelete
1118
+ }
1119
+ ]
118
1120
  }
1121
+ ];
1122
+
1123
+ viewUser(row: any): void {
1124
+ this.router.navigate(['/users', row.id]);
119
1125
  }
1126
+
1127
+ editUser(row: any): void {
1128
+ // Open edit dialog
1129
+ }
1130
+
1131
+ deleteUser(row: any, index: number): void {
1132
+ // Delete logic
1133
+ }
1134
+ ```
1135
+
1136
+ ### Example 9: Dynamic Select Options Based on Row
1137
+
1138
+ ```typescript
1139
+ // Component
1140
+ columns: StMaterialTableColumnModel[] = [
1141
+ { field: 'country', header: 'Country', allowEditColumn: true },
1142
+ {
1143
+ field: 'state',
1144
+ header: 'State',
1145
+ allowEditColumn: true,
1146
+ rowEditType: 'custom-dynamic-select',
1147
+ dynamicRowEditOptions: (row) => {
1148
+ if (row.country === 'USA') {
1149
+ return [
1150
+ { value: 'NY', label: 'New York' },
1151
+ { value: 'CA', label: 'California' },
1152
+ { value: 'TX', label: 'Texas' }
1153
+ ];
1154
+ } else if (row.country === 'UK') {
1155
+ return [
1156
+ { value: 'ENG', label: 'England' },
1157
+ { value: 'SCT', label: 'Scotland' },
1158
+ { value: 'WLS', label: 'Wales' }
1159
+ ];
1160
+ }
1161
+ return [];
1162
+ }
1163
+ }
1164
+ ];
120
1165
  ```
121
1166
 
122
- **When to use autoSaveOnChange:**
123
- - Selection tables with quantity inputs
124
- - Toggle/checkbox columns that should update immediately
125
- - Simple data entry without complex validation
126
- - Better UX when users don't want to click save buttons
1167
+ ---
1168
+
1169
+ ## Best Practices
1170
+
1171
+ 1. **Use `localStorageName`** to persist user preferences (column order, filters, sorting)
1172
+
1173
+ 2. **Enable `lazyLoading`** for large datasets (1000+ records)
1174
+
1175
+ 3. **Use `autoSaveOnChange`** for simple quantity/selection tables where immediate updates are desired
1176
+
1177
+ 4. **Use `setNewDataWithoutRefresh`** when frequently updating data to prevent UI flickering
1178
+
1179
+ 5. **Provide validators** (`canEditRowValidator`, `customEditRowValidator`) to enforce business rules
1180
+
1181
+ 6. **Use custom templates** for complex cell rendering instead of trying to format with `customValueDisplay`
1182
+
1183
+ 7. **Set appropriate column widths** to prevent layout shifts
1184
+
1185
+ 8. **Use `notShowInColumnPick`** for action columns or columns that should always be visible
1186
+
1187
+ 9. **Implement proper error handling** in your event handlers (saveEditedRow, rowDeleted, etc.)
1188
+
1189
+ 10. **Use `selectRowValueDisplay`** when simple field labels aren't enough for selected row display
1190
+
1191
+ ---
1192
+
1193
+ ## Common Patterns
1194
+
1195
+ ### Pattern 1: Master-Detail Table
1196
+ Use `allowExtendRow` with `extendedRowTemplate` to show additional details without navigation.
1197
+
1198
+ ### Pattern 2: Quick Edit Grid
1199
+ Use `autoSaveOnChange` with `setNewDataWithoutRefresh` for spreadsheet-like editing.
1200
+
1201
+ ### Pattern 3: Selection List
1202
+ Use `allowSelectRow` with `selectRowOnlyOne` for choosing a single item (like a lookup).
1203
+
1204
+ ### Pattern 4: CRUD Table
1205
+ Combine `allowEditRow`, `allowCreateRow`, and action handlers for full CRUD operations.
127
1206
 
128
- **Benefits:**
129
- - No save/cancel buttons (cleaner UI)
130
- - ✅ Immediate feedback
131
- - ✅ Works perfectly with row selection
132
- - ✅ Parent receives updates in real-time
1207
+ ### Pattern 5: Filtered Report
1208
+ Use `showGlobalSearch`, column filters, and `localStorageName` for a searchable report with saved preferences.
133
1209
 
134
- ## Code scaffolding
1210
+ ---
135
1211
 
136
- Run `ng generate component component-name --project ngx-st-tables` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ngx-st-tables`.
137
- > Note: Don't forget to add `--project ngx-st-tables` or else it will be added to the default project in your `angular.json` file.
1212
+ ## Troubleshooting
138
1213
 
139
- ## Build
1214
+ ### Table doesn't update when data changes
1215
+ - Ensure you're passing a new array reference: `this.data = [...updatedData]`
1216
+ - Or use `setNewDataWithoutRefresh` if you want in-place updates
140
1217
 
141
- Run `ng build ngx-st-tables` to build the project. The build artifacts will be stored in the `dist/` directory.
1218
+ ### Focus lost during editing
1219
+ - Enable `setNewDataWithoutRefresh` for frequent updates
1220
+ - Ensure data array length doesn't change during edits
142
1221
 
143
- ## Publishing
1222
+ ### Filters not working
1223
+ - Check that columns have `filter: true`
1224
+ - Verify `filterType` is set correctly
1225
+ - For custom filters, provide `customFilterOptions`
144
1226
 
145
- After building your library with `ng build ngx-st-tables`, go to the dist folder `cd dist/ngx-st-tables` and run `npm publish`.
1227
+ ### Lazy loading not triggered
1228
+ - Ensure `lazyLoading` is true
1229
+ - Check that `loadData` event handler is connected
1230
+ - Verify you're setting `dataLength` with total record count
146
1231
 
147
- ## Running unit tests
1232
+ ### Row editing disabled
1233
+ - Check `allowEditRow` is true
1234
+ - Verify columns have `allowEditColumn: true`
1235
+ - Check `canEditRowValidator` isn't returning false
148
1236
 
149
- Run `ng test ngx-st-tables` to execute the unit tests via [Karma](https://karma-runner.github.io).
1237
+ ---
150
1238
 
151
- ## Further help
1239
+ This documentation covers all inputs, outputs, and configuration options for the Material Table component. For additional help, refer to the component source code or contact the development team.
152
1240
 
153
- To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.