@angular-bootstrap/ngbootstrap 0.0.9 → 0.0.10
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
|
@@ -39,6 +39,7 @@ All components are standalone, so you import them directly into your feature com
|
|
|
39
39
|
```ts
|
|
40
40
|
import { Component } from '@angular/core';
|
|
41
41
|
import { Datagrid } from '@angular-bootstrap/ngbootstrap/datagrid';
|
|
42
|
+
import { NgbDatagridDefaultEditService } from '@angular-bootstrap/ngbootstrap/datagrid';
|
|
42
43
|
|
|
43
44
|
interface User {
|
|
44
45
|
id: number;
|
|
@@ -54,6 +55,8 @@ interface User {
|
|
|
54
55
|
<ngb-datagrid
|
|
55
56
|
[columns]="columns"
|
|
56
57
|
[data]="rows"
|
|
58
|
+
[trackBy]="trackById"
|
|
59
|
+
[editService]="editService"
|
|
57
60
|
[enableSorting]="true"
|
|
58
61
|
[enableFiltering]="true"
|
|
59
62
|
[enablePagination]="true"
|
|
@@ -63,6 +66,8 @@ interface User {
|
|
|
63
66
|
`,
|
|
64
67
|
})
|
|
65
68
|
export class UsersComponent {
|
|
69
|
+
trackById = (_: number, row: User) => row.id;
|
|
70
|
+
editService = new NgbDatagridDefaultEditService<User>();
|
|
66
71
|
columns = [
|
|
67
72
|
{ field: 'id', header: 'ID', sortable: true },
|
|
68
73
|
{ field: 'name', header: 'Name', sortable: true, filterable: true },
|
|
@@ -86,6 +91,8 @@ Key datagrid capabilities:
|
|
|
86
91
|
- Column/global filtering (`enableFiltering`, `enableGlobalFilter`, `filtersChange`).
|
|
87
92
|
- Pagination (`enablePagination`, `pageSize`, `pageChange`).
|
|
88
93
|
- Inline add/edit/delete (`enableAdd`, `enableEdit`, `enableDelete`, `rowAdd`, `rowSave`, `rowDelete`).
|
|
94
|
+
- Stable row identity via `trackBy` (defaults to index).
|
|
95
|
+
- Pluggable editing logic via `editService` (implement `NgbDatagridEditService`).
|
|
89
96
|
- Export to PDF/Excel via `exportOptions`.
|
|
90
97
|
|
|
91
98
|
Export requires optional peer dependencies. Install only if you use export:
|
|
@@ -330,3 +337,7 @@ Recommended release flow:
|
|
|
330
337
|
- Run `npm version minor` or `npm version patch` to bump `package.json` and create the tag.
|
|
331
338
|
- Push the commit and tag: `git push origin main --tags`.
|
|
332
339
|
- GitHub Actions will build and publish that tagged version to npm.
|
|
340
|
+
|
|
341
|
+
## Keywords
|
|
342
|
+
|
|
343
|
+
Keywords: ngbootstrap, angular bootstrap, bootstrap 5, angular components, UI library, datagrid, data grid, table, pagination, stepper, wizard, splitter, resizable panes, tree view, typeahead, autocomplete, chips, tags input, drag and drop, dnd, accessibility, a11y, ARIA, reactive forms, standalone components.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Input, Directive, EventEmitter, Output, ChangeDetectionStrategy, Component, inject, Injectable, TemplateRef, QueryList, ContentChildren, ContentChild, InjectionToken,
|
|
2
|
+
import { Input, Directive, EventEmitter, Output, ChangeDetectionStrategy, Component, inject, Injectable, signal, TemplateRef, QueryList, ContentChildren, ContentChild, InjectionToken, Optional, Inject, ElementRef, HostListener, HostBinding, ViewChild, forwardRef, ViewChildren } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
4
|
import { CommonModule } from '@angular/common';
|
|
5
5
|
import * as i2 from '@angular/forms';
|
|
@@ -198,6 +198,105 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
198
198
|
args: [{ providedIn: 'root' }]
|
|
199
199
|
}] });
|
|
200
200
|
|
|
201
|
+
const clone = (value) => {
|
|
202
|
+
try {
|
|
203
|
+
// Prefer structuredClone when available.
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
205
|
+
return globalThis.structuredClone ? globalThis.structuredClone(value) : JSON.parse(JSON.stringify(value));
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const shallowEqual = (a, b) => {
|
|
212
|
+
if (a === b)
|
|
213
|
+
return true;
|
|
214
|
+
if (!a || !b)
|
|
215
|
+
return false;
|
|
216
|
+
const aKeys = Object.keys(a);
|
|
217
|
+
const bKeys = Object.keys(b);
|
|
218
|
+
if (aKeys.length !== bKeys.length)
|
|
219
|
+
return false;
|
|
220
|
+
for (const key of aKeys) {
|
|
221
|
+
if (a[key] !== b[key])
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
return true;
|
|
225
|
+
};
|
|
226
|
+
class NgbDatagridDefaultEditService {
|
|
227
|
+
originals = signal([], ...(ngDevMode ? [{ debugName: "originals" }] : []));
|
|
228
|
+
newRows = signal([], ...(ngDevMode ? [{ debugName: "newRows" }] : []));
|
|
229
|
+
create(data, newRow, _rowIndex, rowId) {
|
|
230
|
+
this.newRows.update((ids) => (ids.some((id) => Object.is(id, rowId)) ? ids : [...ids, rowId]));
|
|
231
|
+
// Baseline for a new row is itself until saved/cancelled.
|
|
232
|
+
this.originals.update((items) => {
|
|
233
|
+
if (items.some((it) => Object.is(it.id, rowId)))
|
|
234
|
+
return items;
|
|
235
|
+
return [...items, { id: rowId, row: clone(newRow) }];
|
|
236
|
+
});
|
|
237
|
+
return [...data, newRow];
|
|
238
|
+
}
|
|
239
|
+
update(data, updatedRow, rowIndex, rowId) {
|
|
240
|
+
// Snapshot original the first time we see this rowId.
|
|
241
|
+
const hasBaseline = this.originals().some((it) => Object.is(it.id, rowId));
|
|
242
|
+
if (!hasBaseline) {
|
|
243
|
+
const current = data[rowIndex];
|
|
244
|
+
if (current != null) {
|
|
245
|
+
this.originals.update((items) => [...items, { id: rowId, row: clone(current) }]);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return this.replaceRow(data, updatedRow, rowIndex);
|
|
249
|
+
}
|
|
250
|
+
remove(data, rowIndex, rowId) {
|
|
251
|
+
this.newRows.update((ids) => ids.filter((id) => !Object.is(id, rowId)));
|
|
252
|
+
this.originals.update((items) => items.filter((it) => !Object.is(it.id, rowId)));
|
|
253
|
+
return this.removeRow(data, rowIndex);
|
|
254
|
+
}
|
|
255
|
+
assignValues(row, values) {
|
|
256
|
+
return { ...row, ...values };
|
|
257
|
+
}
|
|
258
|
+
isNew(rowId) {
|
|
259
|
+
return this.newRows().some((id) => Object.is(id, rowId));
|
|
260
|
+
}
|
|
261
|
+
hasChanges(rowId, currentRow) {
|
|
262
|
+
const baseline = this.originals().find((it) => Object.is(it.id, rowId))?.row;
|
|
263
|
+
if (!baseline)
|
|
264
|
+
return false;
|
|
265
|
+
return !shallowEqual(baseline, currentRow);
|
|
266
|
+
}
|
|
267
|
+
saveChanges(data, _rowIndex, rowId, currentRow) {
|
|
268
|
+
this.newRows.update((ids) => ids.filter((id) => !Object.is(id, rowId)));
|
|
269
|
+
// Once saved, clear baseline tracking (no longer "dirty").
|
|
270
|
+
this.originals.update((items) => items.filter((it) => !Object.is(it.id, rowId)));
|
|
271
|
+
// Data is already updated by `create` or `update` at this point.
|
|
272
|
+
return data.slice();
|
|
273
|
+
}
|
|
274
|
+
cancelChanges(data, rowIndex, rowId) {
|
|
275
|
+
if (this.newRows().some((id) => Object.is(id, rowId))) {
|
|
276
|
+
this.newRows.update((ids) => ids.filter((id) => !Object.is(id, rowId)));
|
|
277
|
+
this.originals.update((items) => items.filter((it) => !Object.is(it.id, rowId)));
|
|
278
|
+
return this.removeRow(data, rowIndex);
|
|
279
|
+
}
|
|
280
|
+
const baseline = this.originals().find((it) => Object.is(it.id, rowId))?.row;
|
|
281
|
+
this.originals.update((items) => items.filter((it) => !Object.is(it.id, rowId)));
|
|
282
|
+
if (!baseline)
|
|
283
|
+
return data.slice();
|
|
284
|
+
return this.replaceRow(data, baseline, rowIndex);
|
|
285
|
+
}
|
|
286
|
+
replaceRow(data, updatedRow, rowIndex) {
|
|
287
|
+
if (rowIndex < 0 || rowIndex >= data.length)
|
|
288
|
+
return data.slice();
|
|
289
|
+
const copy = data.slice();
|
|
290
|
+
copy[rowIndex] = updatedRow;
|
|
291
|
+
return copy;
|
|
292
|
+
}
|
|
293
|
+
removeRow(data, rowIndex) {
|
|
294
|
+
if (rowIndex < 0 || rowIndex >= data.length)
|
|
295
|
+
return data.slice();
|
|
296
|
+
return data.filter((_, i) => i !== rowIndex);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
201
300
|
class JsPdfAdapter {
|
|
202
301
|
async export({ fileName, columns, rows, options }) {
|
|
203
302
|
const { jsPDF } = await import('jspdf');
|
|
@@ -232,7 +331,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
232
331
|
args: [{ selector: '[ngbExportButton]' }]
|
|
233
332
|
}] });
|
|
234
333
|
|
|
235
|
-
const
|
|
334
|
+
const MAX_EMAIL_LENGTH = 254;
|
|
335
|
+
const isReasonableEmail = (value) => {
|
|
336
|
+
if (value == null)
|
|
337
|
+
return false;
|
|
338
|
+
const str = String(value);
|
|
339
|
+
if (!str || str.length > MAX_EMAIL_LENGTH)
|
|
340
|
+
return false;
|
|
341
|
+
// Basic, linear-time check: one "@", non-empty local part, and a domain with at least one ".".
|
|
342
|
+
const at = str.indexOf('@');
|
|
343
|
+
if (at <= 0)
|
|
344
|
+
return false;
|
|
345
|
+
if (str.indexOf('@', at + 1) !== -1)
|
|
346
|
+
return false;
|
|
347
|
+
if (at === str.length - 1)
|
|
348
|
+
return false;
|
|
349
|
+
if (/\s/.test(str))
|
|
350
|
+
return false;
|
|
351
|
+
const dot = str.lastIndexOf('.');
|
|
352
|
+
if (dot <= at + 1)
|
|
353
|
+
return false;
|
|
354
|
+
if (dot === str.length - 1)
|
|
355
|
+
return false;
|
|
356
|
+
return true;
|
|
357
|
+
};
|
|
236
358
|
class Datagrid {
|
|
237
359
|
/** Column definitions to render */
|
|
238
360
|
columns = [];
|
|
@@ -273,6 +395,8 @@ class Datagrid {
|
|
|
273
395
|
};
|
|
274
396
|
theme = 'bootstrap';
|
|
275
397
|
responsive = false;
|
|
398
|
+
trackBy;
|
|
399
|
+
editService;
|
|
276
400
|
// Data hooks for export
|
|
277
401
|
dataProviderAll; // used when pages='all'
|
|
278
402
|
dataProviderSelection; // used when pages='selection'
|
|
@@ -310,31 +434,14 @@ class Datagrid {
|
|
|
310
434
|
saveAttemptedEdit = false;
|
|
311
435
|
addForm = this.fb.group({});
|
|
312
436
|
saveAttemptedNew = false;
|
|
437
|
+
addDraftRowId = null;
|
|
438
|
+
defaultEditService = new NgbDatagridDefaultEditService();
|
|
313
439
|
norm(v) {
|
|
314
440
|
return (v ?? '').toString().toLowerCase().trim();
|
|
315
441
|
}
|
|
316
442
|
keyOf(col) {
|
|
317
443
|
return col.field;
|
|
318
444
|
}
|
|
319
|
-
passesRowFilters(row) {
|
|
320
|
-
// per-column
|
|
321
|
-
for (const col of this.columns) {
|
|
322
|
-
if (!col.filterable)
|
|
323
|
-
continue;
|
|
324
|
-
const key = col.field;
|
|
325
|
-
const q = this.norm(this.filters[key]);
|
|
326
|
-
if (!q)
|
|
327
|
-
continue;
|
|
328
|
-
const cell = this.norm(row[col.field]);
|
|
329
|
-
if (!cell.includes(q))
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
// global
|
|
333
|
-
const g = this.norm(this.globalFilter);
|
|
334
|
-
if (!g)
|
|
335
|
-
return true;
|
|
336
|
-
return this.columns.some(c => this.norm(row[c.field]).includes(g));
|
|
337
|
-
}
|
|
338
445
|
getDefaults() {
|
|
339
446
|
return typeof this.newRowDefaults === 'function'
|
|
340
447
|
? this.newRowDefaults() ?? {}
|
|
@@ -388,16 +495,6 @@ class Datagrid {
|
|
|
388
495
|
}
|
|
389
496
|
return this.fb.group(group);
|
|
390
497
|
}
|
|
391
|
-
rowIsValidAgainst(targetErrors) {
|
|
392
|
-
for (const col of this.columns) {
|
|
393
|
-
if (col.editable === false)
|
|
394
|
-
continue;
|
|
395
|
-
const key = this.keyOf(col);
|
|
396
|
-
if (targetErrors[key])
|
|
397
|
-
return false;
|
|
398
|
-
}
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
498
|
strictEmailValidator() {
|
|
402
499
|
// simple, pragmatic: local@domain.tld (tld >= 2)
|
|
403
500
|
const rx = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
|
|
@@ -405,6 +502,8 @@ class Datagrid {
|
|
|
405
502
|
const v = c.value;
|
|
406
503
|
if (v === null || v === undefined || v === '')
|
|
407
504
|
return null; // let "required" handle empties
|
|
505
|
+
if (`${v}`.length > MAX_EMAIL_LENGTH)
|
|
506
|
+
return { email: true };
|
|
408
507
|
return rx.test(String(v)) ? null : { email: true };
|
|
409
508
|
};
|
|
410
509
|
}
|
|
@@ -438,18 +537,6 @@ class Datagrid {
|
|
|
438
537
|
return true;
|
|
439
538
|
});
|
|
440
539
|
}
|
|
441
|
-
compare(a, b) {
|
|
442
|
-
if (a == null && b == null)
|
|
443
|
-
return 0;
|
|
444
|
-
if (a == null)
|
|
445
|
-
return -1;
|
|
446
|
-
if (b == null)
|
|
447
|
-
return 1;
|
|
448
|
-
if (typeof a === 'string' && typeof b === 'string') {
|
|
449
|
-
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
|
|
450
|
-
}
|
|
451
|
-
return a < b ? -1 : a > b ? 1 : 0;
|
|
452
|
-
}
|
|
453
540
|
get sorted() {
|
|
454
541
|
if (!this.enableSorting || !this.sort.active || !this.sort.direction)
|
|
455
542
|
return this.filtered;
|
|
@@ -611,6 +698,12 @@ class Datagrid {
|
|
|
611
698
|
if (ch['columns'])
|
|
612
699
|
this.rebuildFilterForm();
|
|
613
700
|
}
|
|
701
|
+
getRowId(rowIndex, row) {
|
|
702
|
+
return this.trackBy ? this.trackBy(rowIndex, row) : rowIndex;
|
|
703
|
+
}
|
|
704
|
+
getEditService() {
|
|
705
|
+
return this.editService ?? this.defaultEditService;
|
|
706
|
+
}
|
|
614
707
|
startAdd() {
|
|
615
708
|
if (!this.enableAdd || this.addingNew)
|
|
616
709
|
return;
|
|
@@ -619,6 +712,11 @@ class Datagrid {
|
|
|
619
712
|
this.addingNew = true;
|
|
620
713
|
this.addForm = this.buildFormFromRow(); // defaults
|
|
621
714
|
this.saveAttemptedNew = false;
|
|
715
|
+
// Register a draft row with the edit service so implementations can track "new" state.
|
|
716
|
+
const service = this.getEditService();
|
|
717
|
+
const draft = service.assignValues({}, this.addForm.value);
|
|
718
|
+
this.addDraftRowId = Symbol('ngb-datagrid-new-row');
|
|
719
|
+
service.create(this.data ?? [], draft, this.data.length, this.addDraftRowId);
|
|
622
720
|
}
|
|
623
721
|
saveAdd() {
|
|
624
722
|
if (!this.addingNew || !this.addForm)
|
|
@@ -628,18 +726,28 @@ class Datagrid {
|
|
|
628
726
|
this.addForm.updateValueAndValidity();
|
|
629
727
|
if (this.addForm.invalid)
|
|
630
728
|
return;
|
|
631
|
-
const
|
|
729
|
+
const service = this.getEditService();
|
|
730
|
+
const newRow = service.assignValues({}, this.addForm.value);
|
|
731
|
+
const rowIndex = this.data.length;
|
|
732
|
+
const rowId = this.addDraftRowId ?? this.getRowId(rowIndex, newRow);
|
|
733
|
+
service.create(this.data ?? [], newRow, rowIndex, rowId);
|
|
734
|
+
service.saveChanges(this.data ?? [], rowIndex, rowId, newRow);
|
|
632
735
|
this.rowAdd.emit({ newRow });
|
|
633
736
|
this.addingNew = false;
|
|
634
737
|
this.addForm = this.fb.group({});
|
|
635
738
|
;
|
|
636
739
|
this.saveAttemptedNew = false;
|
|
740
|
+
this.addDraftRowId = null;
|
|
637
741
|
}
|
|
638
742
|
cancelAdd() {
|
|
743
|
+
if (this.addDraftRowId != null) {
|
|
744
|
+
this.getEditService().cancelChanges(this.data ?? [], this.data.length, this.addDraftRowId);
|
|
745
|
+
}
|
|
639
746
|
this.addingNew = false;
|
|
640
747
|
this.addForm = this.fb.group({});
|
|
641
748
|
;
|
|
642
749
|
this.saveAttemptedNew = false;
|
|
750
|
+
this.addDraftRowId = null;
|
|
643
751
|
}
|
|
644
752
|
startEdit(i) {
|
|
645
753
|
if (!this.enableEdit)
|
|
@@ -650,6 +758,9 @@ class Datagrid {
|
|
|
650
758
|
this.editForm = this.buildFormFromRow(this.paged[i]);
|
|
651
759
|
this.saveAttemptedEdit = false;
|
|
652
760
|
const di = this.data.indexOf(row);
|
|
761
|
+
const rowId = this.getRowId(di, this.data[di]);
|
|
762
|
+
// Start tracking baseline for the row (service can snapshot original state).
|
|
763
|
+
this.getEditService().update(this.data ?? [], this.data[di], di, rowId);
|
|
653
764
|
this.rowEdit.emit({ row: this.data[di], index: di });
|
|
654
765
|
}
|
|
655
766
|
saveEdit(i) {
|
|
@@ -662,7 +773,11 @@ class Datagrid {
|
|
|
662
773
|
return;
|
|
663
774
|
const di = this.data.indexOf(this.paged[i]);
|
|
664
775
|
const original = this.data[di];
|
|
665
|
-
const
|
|
776
|
+
const rowId = this.getRowId(di, original);
|
|
777
|
+
const service = this.getEditService();
|
|
778
|
+
const updated = service.assignValues(original, this.editForm.value);
|
|
779
|
+
service.update(this.data ?? [], updated, di, rowId);
|
|
780
|
+
service.saveChanges(this.data ?? [], di, rowId, updated);
|
|
666
781
|
this.rowSave.emit({ original, updated, index: di });
|
|
667
782
|
this.editingIndex = null;
|
|
668
783
|
this.editForm = this.fb.group({});
|
|
@@ -670,6 +785,8 @@ class Datagrid {
|
|
|
670
785
|
}
|
|
671
786
|
cancelEdit(i) {
|
|
672
787
|
const di = this.data.indexOf(this.paged[i]);
|
|
788
|
+
const rowId = this.getRowId(di, this.data[di]);
|
|
789
|
+
this.getEditService().cancelChanges(this.data ?? [], di, rowId);
|
|
673
790
|
this.rowCancel.emit({ row: this.data[di], index: di });
|
|
674
791
|
this.editingIndex = null;
|
|
675
792
|
this.editForm = this.fb.group({}); // empty group
|
|
@@ -677,6 +794,10 @@ class Datagrid {
|
|
|
677
794
|
}
|
|
678
795
|
// For the "Add row" draft
|
|
679
796
|
onNewDraftChange(col) {
|
|
797
|
+
if (this.draftNew) {
|
|
798
|
+
const key = this.keyOf(col);
|
|
799
|
+
this.draftNew = this.getEditService().assignValues(this.draftNew, { [key]: this.draftNew[key] });
|
|
800
|
+
}
|
|
680
801
|
this.validateInto(col, this.draftNew, this.errorsNew);
|
|
681
802
|
}
|
|
682
803
|
validateInto(col, targetDraft, targetErrors) {
|
|
@@ -692,8 +813,7 @@ class Datagrid {
|
|
|
692
813
|
err = 'Required';
|
|
693
814
|
}
|
|
694
815
|
// type checks
|
|
695
|
-
|
|
696
|
-
if (!err && col.type === 'email' && val && !EMAIL_RX.test(String(val)))
|
|
816
|
+
if (!err && col.type === 'email' && val && !isReasonableEmail(val))
|
|
697
817
|
err = 'Invalid email';
|
|
698
818
|
if (!err && col.type === 'number' && val !== '' && val != null && Number.isNaN(Number(val)))
|
|
699
819
|
err = 'Invalid number';
|
|
@@ -710,10 +830,17 @@ class Datagrid {
|
|
|
710
830
|
if (!this.enableDelete)
|
|
711
831
|
return;
|
|
712
832
|
const di = this.dataIndexFromPaged(i);
|
|
713
|
-
|
|
833
|
+
const row = this.data[di];
|
|
834
|
+
const rowId = this.getRowId(di, row);
|
|
835
|
+
this.getEditService().remove(this.data ?? [], di, rowId);
|
|
836
|
+
this.rowDelete.emit({ row, index: di });
|
|
714
837
|
}
|
|
715
838
|
// (optional) better *ngFor performance
|
|
716
|
-
trackRow = (
|
|
839
|
+
trackRow = (index, row) => {
|
|
840
|
+
const di = this.data.indexOf(row);
|
|
841
|
+
const rowIndex = di >= 0 ? di : index;
|
|
842
|
+
return this.trackBy ? this.trackBy(rowIndex, row) : rowIndex;
|
|
843
|
+
};
|
|
717
844
|
toggleSort(field) {
|
|
718
845
|
if (!this.enableSorting)
|
|
719
846
|
return;
|
|
@@ -794,7 +921,7 @@ class Datagrid {
|
|
|
794
921
|
return r === true || (!!r && r.enabled === true);
|
|
795
922
|
}
|
|
796
923
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Datagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
797
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: Datagrid, isStandalone: true, selector: "ngb-datagrid", inputs: { columns: "columns", data: "data", enableSorting: "enableSorting", enableFiltering: "enableFiltering", enableGlobalFilter: "enableGlobalFilter", enablePagination: "enablePagination", enableEdit: "enableEdit", enableDelete: "enableDelete", pageSizeOptions: "pageSizeOptions", enableAdd: "enableAdd", addButtonAriaLabel: "addButtonAriaLabel", addButtonText: "addButtonText", globalFilterAriaLabel: "globalFilterAriaLabel", expandRowAriaLabel: "expandRowAriaLabel", collapseRowAriaLabel: "collapseRowAriaLabel", exportPdfAriaLabel: "exportPdfAriaLabel", exportExcelAriaLabel: "exportExcelAriaLabel", newRowDefaults: "newRowDefaults", strictEmail: "strictEmail", editOnRowClick: "editOnRowClick", singleExpand: "singleExpand", exportOptions: "exportOptions", theme: "theme", responsive: "responsive", dataProviderAll: "dataProviderAll", dataProviderSelection: "dataProviderSelection", pageSize: "pageSize" }, outputs: { rowAdd: "rowAdd", rowEdit: "rowEdit", rowSave: "rowSave", rowCancel: "rowCancel", rowDelete: "rowDelete", sortChange: "sortChange", filtersChange: "filtersChange", pageChange: "pageChange" }, providers: [
|
|
924
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: Datagrid, isStandalone: true, selector: "ngb-datagrid", inputs: { columns: "columns", data: "data", enableSorting: "enableSorting", enableFiltering: "enableFiltering", enableGlobalFilter: "enableGlobalFilter", enablePagination: "enablePagination", enableEdit: "enableEdit", enableDelete: "enableDelete", pageSizeOptions: "pageSizeOptions", enableAdd: "enableAdd", addButtonAriaLabel: "addButtonAriaLabel", addButtonText: "addButtonText", globalFilterAriaLabel: "globalFilterAriaLabel", expandRowAriaLabel: "expandRowAriaLabel", collapseRowAriaLabel: "collapseRowAriaLabel", exportPdfAriaLabel: "exportPdfAriaLabel", exportExcelAriaLabel: "exportExcelAriaLabel", newRowDefaults: "newRowDefaults", strictEmail: "strictEmail", editOnRowClick: "editOnRowClick", singleExpand: "singleExpand", exportOptions: "exportOptions", theme: "theme", responsive: "responsive", trackBy: "trackBy", editService: "editService", dataProviderAll: "dataProviderAll", dataProviderSelection: "dataProviderSelection", pageSize: "pageSize" }, outputs: { rowAdd: "rowAdd", rowEdit: "rowEdit", rowSave: "rowSave", rowCancel: "rowCancel", rowDelete: "rowDelete", sortChange: "sortChange", filtersChange: "filtersChange", pageChange: "pageChange" }, providers: [
|
|
798
925
|
{ provide: PdfExportAdapter, useClass: JsPdfAdapter },
|
|
799
926
|
{ provide: ExcelExportAdapter, useClass: XlsxAdapter }
|
|
800
927
|
], queries: [{ propertyName: "exportButtonDir", first: true, predicate: ExportButtonDirective, descendants: true }, { propertyName: "rowDetailTpl", first: true, predicate: NgbRowDetailTemplate, descendants: true }, { propertyName: "cellTplQ", predicate: NgbCellTemplate }, { propertyName: "editTplQ", predicate: NgbEditorTemplate }, { propertyName: "filterTplQ", predicate: NgbFilterTemplate }, { propertyName: "globalTplQ", predicate: NgbGlobalFilterTemplate }], usesOnChanges: true, ngImport: i0, template: "<!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->\n<!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->\n<div class=\"ngb-grid\" [attr.data-theme]=\"theme\" [class.ngb-responsive]=\"isResponsiveEnabled()\">\n <!-- Export toolbar -->\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"exportOptions?.enabled\">\n <ng-container *ngIf=\"exportButtonTpl; else defaultExportBtns\"\n [ngTemplateOutlet]=\"exportButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: triggerExport }\">\n </ng-container>\n\n <ng-template #defaultExportBtns>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary me-2\"\n *ngIf=\"exportOptions.type === 'pdf' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('pdf')\"\n [attr.aria-label]=\"exportAriaLabel('pdf')\">\n Export to PDF\n </button>\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n *ngIf=\"exportOptions.type === 'excel' || exportOptions.type === 'both'\"\n [disabled]=\"exporting\"\n (click)=\"export('excel')\"\n [attr.aria-label]=\"exportAriaLabel('excel')\">\n Export to Excel\n </button>\n </ng-template>\n </div>\n <div class=\"d-flex justify-content-end mb-2\" *ngIf=\"enableAdd\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-primary\"\n (click)=\"startAdd()\"\n [disabled]=\"addingNew\"\n [attr.aria-label]=\"addButtonAriaLabel || addButtonText\"\n >\n {{ addButtonText }}\n </button>\n </div>\n <!-- Global filter -->\n <div class=\"mb-2\" *ngIf=\"enableFiltering && enableGlobalFilter\">\n <ng-container\n *ngIf=\"globalTpl; else defaultGlobalFilter\"\n [ngTemplateOutlet]=\"globalTpl?.template\"\n [ngTemplateOutletContext]=\"{ $implicit: globalFilterCtrl }\"\n >\n </ng-container>\n\n <ng-template #defaultGlobalFilter>\n <input\n type=\"search\"\n class=\"form-control form-control-sm\"\n placeholder=\"Search all columns...\"\n [formControl]=\"globalFilterCtrl\"\n [attr.aria-label]=\"globalFilterAriaLabel\"\n />\n </ng-template>\n </div>\n\n <table class=\"table table-bordered\"\n role=\"grid\"\n [attr.aria-readonly]=\"(enableEdit || enableAdd) ? 'false' : 'true'\">\n <thead class=\"thead-light\">\n <tr>\n <th *ngIf=\"rowDetailTpl\" style=\"width:1%\" scope=\"col\" aria-hidden=\"true\"></th>\n <th\n *ngFor=\"let col of columns\"\n [attr.data-title]=\"col.header\"\n [class.sortable]=\"enableSorting && col.sortable\"\n scope=\"col\"\n [attr.aria-sort]=\"enableSorting && col.sortable ? ariaSortFor(col.field) : null\"\n >\n <ng-container *ngIf=\"enableSorting && col.sortable; else plainHeader\">\n <button\n type=\"button\"\n class=\"btn btn-link p-0 text-start w-100\"\n (click)=\"toggleSort(col.field)\"\n [attr.aria-label]=\"sortButtonAriaLabel(col)\"\n >\n <span>{{ col.header }}</span>\n <span\n class=\"sort-indicator\"\n *ngIf=\"enableSorting && sort.active === col.field\"\n aria-hidden=\"true\"\n >\n {{\n sort.direction === 'asc'\n ? '\u25B2'\n : sort.direction === 'desc'\n ? '\u25BC'\n : ''\n }}\n </span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span>{{ col.header }}</span>\n </ng-template>\n </th>\n <th\n *ngIf=\"enableEdit || enableDelete\"\n class=\"text-center\"\n scope=\"col\"\n style=\"width: 1%\"\n >\n Actions\n </th>\n </tr>\n\n <!-- Per-column filters -->\n <tr *ngIf=\"anyFilterable\" [formGroup]=\"filterForm\">\n <th *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container *ngIf=\"col.filterable\">\n <ng-container *ngIf=\"filterTpls[col.field] as ft; else defaultFilter\">\n <ng-container\n [ngTemplateOutlet]=\"ft.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: filterForm.get(col.field),\n control: filterForm.get(col.field),\n col: col\n }\"\n >\n </ng-container>\n </ng-container>\n <ng-template #defaultFilter>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"columnFilterAriaLabel(col)\"\n />\n </ng-template>\n </ng-container>\n </th>\n <th *ngIf=\"enableEdit || enableDelete\"></th>\n </tr>\n </thead>\n\n <tbody>\n <!-- ADD NEW ROW -->\n <tr *ngIf=\"addingNew\" [formGroup]=\"addForm\">\n <!-- blank caret cell to keep alignment when detail column is present -->\n <td *ngIf=\"rowDetailTpl\"></td>\n\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <ng-container [ngSwitch]=\"col.type\">\n <!-- boolean -->\n <div\n *ngSwitchCase=\"'boolean'\"\n class=\"form-check m-0\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </div>\n\n <!-- number/email/date/text -->\n <input\n *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [class.is-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.invalid ? 'add-error-' + col.field : null\"\n />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(addForm.get(col.field)?.touched || saveAttemptedNew) && addForm.get(col.field)?.errors as e\"\n [attr.id]=\"'add-error-' + col.field\"\n role=\"alert\">\n <ng-container *ngIf=\"e['required']\">Required</ng-container>\n <ng-container *ngIf=\"e['email']\">Invalid email</ng-container>\n <ng-container *ngIf=\"e['number']\">Invalid number</ng-container>\n <ng-container *ngIf=\"e['date']\">Invalid date</ng-container>\n </div>\n </td>\n\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveAdd()\" [disabled]=\"addForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelAdd()\">Cancel</button>\n </td>\n </tr>\n\n <!-- DATA ROWS + DETAIL ROWS -->\n <ng-container *ngFor=\"let row of paged; let i = index; trackBy: trackRow\">\n\n <!-- DATA ROW (click-to-edit supported) -->\n <tr (click)=\"onRowClick($event, i)\" [formGroup]=\"editForm\">\n\n <!-- caret/expander cell (left-most) -->\n <td *ngIf=\"rowDetailTpl\" class=\"text-center align-middle\">\n <button\n type=\"button\"\n class=\"expand btn btn-link p-0\"\n (click)=\"$event.stopPropagation(); toggleExpand(i)\"\n [attr.aria-expanded]=\"isExpanded(i)\"\n [attr.aria-controls]=\"'dg-row-detail-' + i\"\n [attr.aria-label]=\"isExpanded(i) ? collapseRowAriaLabel : expandRowAriaLabel\">\n {{ isExpanded(i) ? '-' : '+' }}\n </button>\n </td>\n\n <!-- DATA CELLS -->\n <td *ngFor=\"let col of columns\" [attr.data-title]=\"col.header\">\n <!-- EDIT MODE -->\n <ng-container *ngIf=\"editingIndex === i && (col.editable ?? true); else readCell\">\n <!-- editor template override -->\n <ng-container *ngIf=\"editTpls[col.field] as et; else defaultEditor\"\n [ngTemplateOutlet]=\"et.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: editForm.get(col.field),\n control: editForm.get(col.field),\n row: row, col: col, form: editForm, index: i, isNew: false\n }\">\n </ng-container>\n\n <!-- default editors -->\n <ng-template #defaultEditor>\n <ng-container [ngSwitch]=\"col.type\">\n <div *ngSwitchCase=\"'boolean'\" class=\"form-check m-0\">\n <input type=\"checkbox\"\n class=\"form-check-input\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </div>\n <select *ngSwitchCase=\"'select'\"\n class=\"form-select form-select-sm\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\">\n <option *ngFor=\"let o of col.options ?? []\" [ngValue]=\"o.value\">{{ o.label }}</option>\n </select>\n <input *ngSwitchDefault\n class=\"form-control form-control-sm\"\n [attr.type]=\"col.type === 'number' ? 'number' :\n col.type === 'email' ? 'email' :\n col.type === 'date' ? 'date' : 'text'\"\n [formControlName]=\"col.field\"\n [attr.aria-label]=\"inputAriaLabel(col)\"\n [attr.aria-invalid]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'true' : null\"\n [attr.aria-describedby]=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.invalid ? 'edit-error-' + col.field : null\" />\n </ng-container>\n\n <div class=\"invalid-feedback d-block\"\n *ngIf=\"(editForm?.touched || saveAttemptedEdit) && editForm?.get(col.field)?.errors as e\"\n [attr.id]=\"'edit-error-' + col.field\"\n role=\"alert\">\n <span *ngIf=\"e['required']\">Required</span>\n <span *ngIf=\"e['email']\">Invalid email</span>\n <span *ngIf=\"e['number']\">Invalid number</span>\n <span *ngIf=\"e['date']\">Invalid date</span>\n </div>\n </ng-template>\n </ng-container>\n\n <!-- READ MODE (with optional cell template) -->\n <ng-template #readCell>\n <ng-container *ngIf=\"cellTpls[col.field] as ct; else defaultCell\"\n [ngTemplateOutlet]=\"ct.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row[col.field], row: row, col: col, index: i }\">\n </ng-container>\n <ng-template #defaultCell>\n <ng-container [ngSwitch]=\"col.type\">\n <span *ngSwitchCase=\"'boolean'\">{{ row[col.field] ? 'Yes' : 'No' }}</span>\n <span *ngSwitchDefault>{{ row[col.field] }}</span>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n\n <!-- ACTIONS -->\n <td *ngIf=\"enableEdit || enableDelete\" class=\"text-nowrap text-center\">\n <ng-container *ngIf=\"editingIndex !== i; else editBtns\">\n <button type=\"button\" *ngIf=\"enableEdit\" class=\"btn btn-sm btn-outline-primary me-1 no-edit-trigger\" (click)=\"startEdit(i)\">Edit</button>\n <button type=\"button\" *ngIf=\"enableDelete\" class=\"btn btn-sm btn-outline-danger no-edit-trigger\" (click)=\"deleteRow(i)\">Delete</button>\n </ng-container>\n <ng-template #editBtns>\n <button type=\"button\" class=\"btn btn-sm btn-success me-1\" (click)=\"saveEdit(i)\" [disabled]=\"editForm.invalid\">Save</button>\n <button type=\"button\" class=\"btn btn-sm btn-secondary\" (click)=\"cancelEdit(i)\">Cancel</button>\n </ng-template>\n </td>\n </tr>\n\n <!-- DETAIL ROW (spans all columns) -->\n <tr *ngIf=\"rowDetailTpl && isExpanded(i)\" [attr.id]=\"'dg-row-detail-' + i\">\n <td [attr.colspan]=\"detailColspan\" role=\"region\">\n <ng-container [ngTemplateOutlet]=\"rowDetailTpl.template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\">\n </ng-container>\n </td>\n </tr>\n\n </ng-container>\n </tbody>\n\n </table>\n\n <!-- Footer (left = count, center = pagination, right = page size) -->\n <div *ngIf=\"enablePagination\" class=\"d-flex align-items-center justify-content-between mt-2\">\n <!-- left: count -->\n <div class=\"small text-muted\" aria-live=\"polite\">\n {{ startIndex }} - {{ endIndex }} of {{ sorted.length }}\n\n </div>\n\n <!-- center: pager -->\n <div class=\"flex-grow-1 d-flex justify-content-center\">\n <ngb-pagination\n [page]=\"page\"\n [pageSize]=\"pageSize\"\n [collectionSize]=\"sorted.length\"\n [maxSize]=\"5\"\n (pageChange)=\"onPage($event)\">\n </ngb-pagination>\n </div>\n\n <!-- right: rows per page -->\n <div class=\"d-flex align-items-center gap-2\">\n <label class=\"form-label form-label-sm mb-0\" for=\"pageSize\">Rows:</label>\n <select\n id=\"pageSize\"\n class=\"form-select form-select-sm\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSize($event)\"\n aria-label=\"Rows per page\">\n <option *ngFor=\"let s of pageSizeOptions\" [value]=\"s\">{{ s }}</option>\n </select>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.table{margin-bottom:.5rem}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sort-indicator{margin-left:.35rem;font-size:.75rem}.expand{cursor:pointer;font-size:24px;line-height:18px;display:block}.ngb-grid[data-theme=material]{--ngb-primary: #3f51b5}.ngb-grid[data-theme=material] .btn{border-color:var(--ngb-primary)}.ngb-grid[data-theme=material] table.table th,.ngb-grid[data-theme=material] table.table td{border-bottom:1px solid #e5e7eb}.ngb-grid[data-theme=tailwind]{--ngb-primary: rgb(29 78 216)}.ngb-grid[data-theme=tailwind] .btn{border-color:var(--ngb-primary);border-radius:.75rem}.ngb-grid[data-theme=tailwind] table.table th,.ngb-grid[data-theme=tailwind] table.table td{border-bottom:1px solid #e5e7eb;padding:.5rem}.ngb-responsive .table{width:100%}@media(max-width:768px){.ngb-responsive thead{display:none}.ngb-responsive tbody tr{display:grid;grid-template-columns:1fr;gap:.5rem;border:1px solid #e5e7eb;border-radius:.75rem;padding:.75rem;margin-bottom:.75rem}.ngb-responsive tbody td{display:grid;grid-template-columns:8rem 1fr}.ngb-responsive tbody td:before{content:attr(data-title);font-weight:600;opacity:.75;padding-right:.5rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NgbPaginationComponent, selector: "ngb-pagination", inputs: ["page", "pageSize", "collectionSize", "maxSize"], outputs: ["pageChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
@@ -853,6 +980,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
853
980
|
type: Input
|
|
854
981
|
}], responsive: [{
|
|
855
982
|
type: Input
|
|
983
|
+
}], trackBy: [{
|
|
984
|
+
type: Input
|
|
985
|
+
}], editService: [{
|
|
986
|
+
type: Input
|
|
856
987
|
}], dataProviderAll: [{
|
|
857
988
|
type: Input
|
|
858
989
|
}], dataProviderSelection: [{
|
|
@@ -3529,5 +3660,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
3529
3660
|
* Generated bundle index. Do not edit.
|
|
3530
3661
|
*/
|
|
3531
3662
|
|
|
3532
|
-
export { DATAGRID_TEMPLATE_DIRECTIVES, DND_I18N, DND_LIVE_ANNOUNCE, Datagrid, ExcelExportAdapter, ExportButtonDirective, JsPdfAdapter, NgbCellTemplate, NgbChipsComponent, NgbDndItemDirective, NgbDndListDirective, NgbDndState, NgbEditorTemplate, NgbExportService, NgbFilterTemplate, NgbGlobalFilterTemplate, NgbLiveAnnouncer, NgbPaginationComponent, NgbRowDetailTemplate, NgbSplitterComponent, NgbSplitterPaneComponent, NgbStepLabelDirective, NgbStepperComponent, NgbTreeComponent, NgbTypeaheadComponent, PdfExportAdapter, XlsxAdapter, defaultDndI18n };
|
|
3663
|
+
export { DATAGRID_TEMPLATE_DIRECTIVES, DND_I18N, DND_LIVE_ANNOUNCE, Datagrid, ExcelExportAdapter, ExportButtonDirective, JsPdfAdapter, NgbCellTemplate, NgbChipsComponent, NgbDatagridDefaultEditService, NgbDndItemDirective, NgbDndListDirective, NgbDndState, NgbEditorTemplate, NgbExportService, NgbFilterTemplate, NgbGlobalFilterTemplate, NgbLiveAnnouncer, NgbPaginationComponent, NgbRowDetailTemplate, NgbSplitterComponent, NgbSplitterPaneComponent, NgbStepLabelDirective, NgbStepperComponent, NgbTreeComponent, NgbTypeaheadComponent, PdfExportAdapter, XlsxAdapter, defaultDndI18n };
|
|
3533
3664
|
//# sourceMappingURL=angular-bootstrap-ngbootstrap.mjs.map
|