@nlabtech/nlabs-grid 1.1.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 +638 -0
- package/fesm2022/nlabtech-nlabs-grid.mjs +1881 -0
- package/fesm2022/nlabtech-nlabs-grid.mjs.map +1 -0
- package/package.json +23 -0
- package/types/nlabtech-nlabs-grid.d.ts +444 -0
package/README.md
ADDED
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
# nlabs-grid
|
|
2
|
+
|
|
3
|
+
A modern, feature-rich, and highly customizable Angular data grid component built for Angular 21+ with full theme support and enterprise-grade functionality.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### Core Features
|
|
8
|
+
- **Modern Angular**: Built with Angular 21+ using standalone components
|
|
9
|
+
- **TypeScript**: Full TypeScript support with type safety
|
|
10
|
+
- **Reactive Design**: Built with signals and reactive patterns
|
|
11
|
+
- **Theme Support**: Built-in light/dark theme with customizable CSS variables
|
|
12
|
+
- **Responsive**: Mobile-friendly and responsive design
|
|
13
|
+
|
|
14
|
+
### Data Management
|
|
15
|
+
- **Lazy Loading**: Server-side pagination with OData adapter
|
|
16
|
+
- **Local Data**: Client-side data handling
|
|
17
|
+
- **Sorting**: Multi-column sorting support
|
|
18
|
+
- **Filtering**: Per-column filtering with various filter types
|
|
19
|
+
- **Pagination**: Configurable page sizes and navigation
|
|
20
|
+
|
|
21
|
+
### UI Features
|
|
22
|
+
- **Row Selection**: Single and multi-row selection with custom checkboxes
|
|
23
|
+
- **Column Reordering**: Drag-and-drop column reordering
|
|
24
|
+
- **Column Resizing**: Interactive column width adjustment
|
|
25
|
+
- **Column Chooser**: Show/hide columns dynamically
|
|
26
|
+
- **Custom Templates**: Support for custom cell, header, footer, and action templates
|
|
27
|
+
- **Actions Column**: Customizable action buttons (edit, delete, view, etc.)
|
|
28
|
+
- **Empty State**: Customizable empty data message
|
|
29
|
+
|
|
30
|
+
### Advanced Features
|
|
31
|
+
- **Custom Checkbox Design**: Modern, corporate-style checkboxes with smooth animations
|
|
32
|
+
- **Actions Template**: Fully customizable action buttons via ng-template
|
|
33
|
+
- **Global Search**: Search across all columns
|
|
34
|
+
- **Export Options**: Excel and PDF export capabilities
|
|
35
|
+
- **State Management**: Preserve grid state (sorting, filtering, pagination)
|
|
36
|
+
|
|
37
|
+
## Links
|
|
38
|
+
|
|
39
|
+
- **GitHub Repository**: [https://github.com/NlabsNpmPackages/nlabs-grid](https://github.com/NlabsNpmPackages/nlabs-grid)
|
|
40
|
+
- **Example Usage**: [https://github.com/NlabsGlobalFullStack/nlabs-data-grid-example](https://github.com/NlabsGlobalFullStack/nlabs-data-grid-example)
|
|
41
|
+
- **npm Package**: [https://www.npmjs.com/package/nlabs-grid](https://www.npmjs.com/package/nlabs-grid)
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install nlabs-grid
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### 1. Import the Component
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { Component } from '@angular/core';
|
|
55
|
+
import { DataGridComponent, GridConfig, ODataAdapter } from 'nlabs-grid';
|
|
56
|
+
import { HttpClient } from '@angular/common/http';
|
|
57
|
+
|
|
58
|
+
@Component({
|
|
59
|
+
selector: 'app-root',
|
|
60
|
+
standalone: true,
|
|
61
|
+
imports: [DataGridComponent],
|
|
62
|
+
template: `
|
|
63
|
+
<nlabs-data-grid
|
|
64
|
+
[config]="gridConfig"
|
|
65
|
+
[adapter]="dataAdapter"
|
|
66
|
+
[autoLoad]="true"
|
|
67
|
+
[lazy]="true"
|
|
68
|
+
[theme]="'dark'"
|
|
69
|
+
/>
|
|
70
|
+
`
|
|
71
|
+
})
|
|
72
|
+
export class AppComponent {
|
|
73
|
+
gridConfig: GridConfig = {
|
|
74
|
+
columns: [
|
|
75
|
+
{ field: 'id', header: 'ID', sortable: true, width: '80px' },
|
|
76
|
+
{ field: 'name', header: 'Name', sortable: true, filterable: true },
|
|
77
|
+
{ field: 'email', header: 'Email', sortable: true, filterable: true }
|
|
78
|
+
],
|
|
79
|
+
pageSize: 10,
|
|
80
|
+
sortable: true,
|
|
81
|
+
filterable: true
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
dataAdapter: ODataAdapter;
|
|
85
|
+
|
|
86
|
+
constructor(private http: HttpClient) {
|
|
87
|
+
this.dataAdapter = new ODataAdapter(http, 'https://api.example.com/odata/Users');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2. Basic Configuration
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
gridConfig: GridConfig = {
|
|
96
|
+
columns: [
|
|
97
|
+
{
|
|
98
|
+
field: 'id',
|
|
99
|
+
header: 'ID',
|
|
100
|
+
sortable: true,
|
|
101
|
+
filterable: false,
|
|
102
|
+
width: '80px',
|
|
103
|
+
type: 'number'
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
field: 'name',
|
|
107
|
+
header: 'Name',
|
|
108
|
+
sortable: true,
|
|
109
|
+
filterable: true,
|
|
110
|
+
width: '200px'
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
field: 'active',
|
|
114
|
+
header: 'Active',
|
|
115
|
+
type: 'boolean',
|
|
116
|
+
format: (value: boolean) => value ? '✓ Active' : '✗ Inactive'
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
pageSize: 10,
|
|
120
|
+
pageSizeOptions: [5, 10, 25, 50, 100],
|
|
121
|
+
sortable: true,
|
|
122
|
+
filterable: true,
|
|
123
|
+
selectable: true,
|
|
124
|
+
multiSelect: true,
|
|
125
|
+
showCheckboxColumn: true,
|
|
126
|
+
checkboxColumnWidth: '60px',
|
|
127
|
+
showActions: true,
|
|
128
|
+
actionsHeader: 'Actions',
|
|
129
|
+
actionsWidth: '180px',
|
|
130
|
+
reorderable: true,
|
|
131
|
+
resizable: true,
|
|
132
|
+
showHeader: true,
|
|
133
|
+
showFooter: true,
|
|
134
|
+
emptyMessage: 'No records found'
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Advanced Usage
|
|
139
|
+
|
|
140
|
+
### Selection with Custom Checkboxes
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// Enable selection
|
|
144
|
+
gridConfig: GridConfig = {
|
|
145
|
+
selectable: true,
|
|
146
|
+
multiSelect: true,
|
|
147
|
+
showCheckboxColumn: true,
|
|
148
|
+
checkboxColumnWidth: '60px',
|
|
149
|
+
// ... other config
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Handle selection events
|
|
153
|
+
onRowSelect(row: any): void {
|
|
154
|
+
console.log('Row selected:', row);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
onRowUnselect(row: any): void {
|
|
158
|
+
console.log('Row unselected:', row);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<nlabs-data-grid
|
|
164
|
+
[config]="gridConfig"
|
|
165
|
+
[adapter]="dataAdapter"
|
|
166
|
+
(rowSelect)="onRowSelect($event)"
|
|
167
|
+
(rowUnselect)="onRowUnselect($event)"
|
|
168
|
+
/>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Custom Actions Column
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { GridColumnCommandTemplateDirective } from 'nlabs-grid';
|
|
175
|
+
|
|
176
|
+
@Component({
|
|
177
|
+
imports: [DataGridComponent, GridColumnCommandTemplateDirective],
|
|
178
|
+
// ...
|
|
179
|
+
})
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<nlabs-data-grid
|
|
184
|
+
[config]="gridConfig"
|
|
185
|
+
[adapter]="dataAdapter">
|
|
186
|
+
|
|
187
|
+
<!-- Custom Actions Template -->
|
|
188
|
+
<ng-template nlabsGridColumnCommandTemplate="actions" let-row>
|
|
189
|
+
<button class="btn-edit" (click)="onEdit(row)">
|
|
190
|
+
✏️ Edit
|
|
191
|
+
</button>
|
|
192
|
+
<button class="btn-delete" (click)="onDelete(row)">
|
|
193
|
+
🗑️ Delete
|
|
194
|
+
</button>
|
|
195
|
+
<button class="btn-view" (click)="onView(row)">
|
|
196
|
+
👁️ View
|
|
197
|
+
</button>
|
|
198
|
+
</ng-template>
|
|
199
|
+
</nlabs-data-grid>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Custom Footer Template
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { GridFooterTemplateDirective } from 'nlabs-grid';
|
|
206
|
+
|
|
207
|
+
@Component({
|
|
208
|
+
imports: [DataGridComponent, GridFooterTemplateDirective],
|
|
209
|
+
// ...
|
|
210
|
+
})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```html
|
|
214
|
+
<nlabs-data-grid [config]="gridConfig" [adapter]="dataAdapter">
|
|
215
|
+
<ng-template nlabsGridFooterTemplate let-data let-total="total">
|
|
216
|
+
<div class="custom-footer">
|
|
217
|
+
<span>Total Records: {{ total }}</span>
|
|
218
|
+
<span>Showing {{ data.length }} items</span>
|
|
219
|
+
</div>
|
|
220
|
+
</ng-template>
|
|
221
|
+
</nlabs-data-grid>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### OData Integration
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { ODataAdapter } from 'nlabs-grid';
|
|
228
|
+
|
|
229
|
+
// Create adapter
|
|
230
|
+
this.odataAdapter = new ODataAdapter<User>(
|
|
231
|
+
this.http,
|
|
232
|
+
'http://localhost:5210/odata/Users'
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
// Use with grid
|
|
236
|
+
<nlabs-data-grid
|
|
237
|
+
[adapter]="odataAdapter"
|
|
238
|
+
[lazy]="true"
|
|
239
|
+
[autoLoad]="true"
|
|
240
|
+
/>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### REST API Integration
|
|
244
|
+
|
|
245
|
+
For standard REST endpoints (non-OData), use the `RestAdapter`:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { RestAdapter, RestAdapterConfig } from 'nlabs-grid';
|
|
249
|
+
|
|
250
|
+
// Simple usage - API returns { data: [], total: number }
|
|
251
|
+
this.restAdapter = new RestAdapter<User>(
|
|
252
|
+
this.http,
|
|
253
|
+
'http://localhost:5000/api/users'
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Custom configuration
|
|
257
|
+
this.restAdapter = new RestAdapter<User>(
|
|
258
|
+
this.http,
|
|
259
|
+
'http://localhost:5000/api/users',
|
|
260
|
+
{
|
|
261
|
+
usePagination: 'page', // Use page/pageSize instead of skip/take
|
|
262
|
+
pageParam: 'page', // Query param name for page
|
|
263
|
+
pageSizeParam: 'limit', // Query param name for page size
|
|
264
|
+
sortParam: 'orderBy', // Query param name for sorting
|
|
265
|
+
dataKey: 'result.items', // Nested path to data array
|
|
266
|
+
totalKey: 'result.totalCount' // Nested path to total count
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
// With custom response mapper for complex APIs
|
|
271
|
+
this.restAdapter = new RestAdapter<User>(
|
|
272
|
+
this.http,
|
|
273
|
+
'http://localhost:5000/api/users',
|
|
274
|
+
{
|
|
275
|
+
responseMapper: (response) => ({
|
|
276
|
+
data: response.payload.users,
|
|
277
|
+
total: response.meta.pagination.total
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### REST Backend Examples
|
|
284
|
+
|
|
285
|
+
**ASP.NET Core Minimal API:**
|
|
286
|
+
|
|
287
|
+
```csharp
|
|
288
|
+
// Program.cs
|
|
289
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
290
|
+
builder.Services.AddDbContext<AppDbContext>();
|
|
291
|
+
|
|
292
|
+
var app = builder.Build();
|
|
293
|
+
|
|
294
|
+
// GET /api/users?skip=0&pageSize=10&sort=name&filter=...
|
|
295
|
+
app.MapGet("/api/users", async (
|
|
296
|
+
AppDbContext db,
|
|
297
|
+
int skip = 0,
|
|
298
|
+
int pageSize = 10,
|
|
299
|
+
string? sort = null,
|
|
300
|
+
string? filter = null) =>
|
|
301
|
+
{
|
|
302
|
+
var query = db.Users.AsQueryable();
|
|
303
|
+
|
|
304
|
+
// Apply filtering
|
|
305
|
+
if (!string.IsNullOrEmpty(filter))
|
|
306
|
+
{
|
|
307
|
+
query = query.Where(u => u.Name.Contains(filter) || u.Email.Contains(filter));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Apply sorting
|
|
311
|
+
if (!string.IsNullOrEmpty(sort))
|
|
312
|
+
{
|
|
313
|
+
query = sort.EndsWith(" desc")
|
|
314
|
+
? query.OrderByDescending(u => EF.Property<object>(u, sort.Replace(" desc", "")))
|
|
315
|
+
: query.OrderBy(u => EF.Property<object>(u, sort));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Get total count before pagination
|
|
319
|
+
var total = await query.CountAsync();
|
|
320
|
+
|
|
321
|
+
// Apply pagination
|
|
322
|
+
var data = await query.Skip(skip).Take(pageSize).ToListAsync();
|
|
323
|
+
|
|
324
|
+
return Results.Ok(new { data, total });
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
app.Run();
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**ASP.NET Core Controller:**
|
|
331
|
+
|
|
332
|
+
```csharp
|
|
333
|
+
[ApiController]
|
|
334
|
+
[Route("api/[controller]")]
|
|
335
|
+
public class UsersController : ControllerBase
|
|
336
|
+
{
|
|
337
|
+
private readonly AppDbContext _context;
|
|
338
|
+
|
|
339
|
+
public UsersController(AppDbContext context)
|
|
340
|
+
{
|
|
341
|
+
_context = context;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
[HttpGet]
|
|
345
|
+
public async Task<IActionResult> GetUsers(
|
|
346
|
+
int skip = 0,
|
|
347
|
+
int pageSize = 10,
|
|
348
|
+
string? sort = null,
|
|
349
|
+
string? filter = null)
|
|
350
|
+
{
|
|
351
|
+
var query = _context.Users.AsQueryable();
|
|
352
|
+
|
|
353
|
+
// Apply filtering
|
|
354
|
+
if (!string.IsNullOrEmpty(filter))
|
|
355
|
+
{
|
|
356
|
+
query = query.Where(u =>
|
|
357
|
+
u.Name.Contains(filter) ||
|
|
358
|
+
u.Email.Contains(filter));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Apply sorting
|
|
362
|
+
if (!string.IsNullOrEmpty(sort))
|
|
363
|
+
{
|
|
364
|
+
var descending = sort.EndsWith(" desc");
|
|
365
|
+
var field = sort.Replace(" desc", "").Replace(" asc", "");
|
|
366
|
+
|
|
367
|
+
query = descending
|
|
368
|
+
? query.OrderByDescending(u => EF.Property<object>(u, field))
|
|
369
|
+
: query.OrderBy(u => EF.Property<object>(u, field));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Get total count
|
|
373
|
+
var total = await query.CountAsync();
|
|
374
|
+
|
|
375
|
+
// Apply pagination
|
|
376
|
+
var data = await query
|
|
377
|
+
.Skip(skip)
|
|
378
|
+
.Take(pageSize)
|
|
379
|
+
.ToListAsync();
|
|
380
|
+
|
|
381
|
+
return Ok(new { data, total });
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Page-based pagination example:**
|
|
387
|
+
|
|
388
|
+
```csharp
|
|
389
|
+
// GET /api/users?page=1&limit=10
|
|
390
|
+
app.MapGet("/api/users", async (
|
|
391
|
+
AppDbContext db,
|
|
392
|
+
int page = 1,
|
|
393
|
+
int limit = 10) =>
|
|
394
|
+
{
|
|
395
|
+
var total = await db.Users.CountAsync();
|
|
396
|
+
var data = await db.Users
|
|
397
|
+
.Skip((page - 1) * limit)
|
|
398
|
+
.Take(limit)
|
|
399
|
+
.ToListAsync();
|
|
400
|
+
|
|
401
|
+
return Results.Ok(new { data, total });
|
|
402
|
+
});
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
// Angular - use page-based pagination
|
|
407
|
+
this.restAdapter = new RestAdapter<User>(
|
|
408
|
+
this.http,
|
|
409
|
+
'http://localhost:5000/api/users',
|
|
410
|
+
{
|
|
411
|
+
usePagination: 'page',
|
|
412
|
+
pageParam: 'page',
|
|
413
|
+
pageSizeParam: 'limit'
|
|
414
|
+
}
|
|
415
|
+
);
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### RestAdapterConfig Options
|
|
419
|
+
|
|
420
|
+
| Option | Type | Default | Description |
|
|
421
|
+
|--------|------|---------|-------------|
|
|
422
|
+
| `usePagination` | `'page' \| 'skip'` | `'skip'` | Pagination style |
|
|
423
|
+
| `pageParam` | `string` | `'page'` | Query param for page number |
|
|
424
|
+
| `pageSizeParam` | `string` | `'pageSize'` | Query param for page size |
|
|
425
|
+
| `skipParam` | `string` | `'skip'` | Query param for skip count |
|
|
426
|
+
| `sortParam` | `string` | `'sort'` | Query param for sorting |
|
|
427
|
+
| `filterParam` | `string` | `'filter'` | Query param for filtering |
|
|
428
|
+
| `selectParam` | `string` | `'fields'` | Query param for field selection |
|
|
429
|
+
| `dataKey` | `string` | `'data'` | Response property for data array (supports nested paths) |
|
|
430
|
+
| `totalKey` | `string` | `'total'` | Response property for total count (supports nested paths) |
|
|
431
|
+
| `responseMapper` | `function` | - | Custom function to map response to `{ data, total }` |
|
|
432
|
+
|
|
433
|
+
### Theme Support
|
|
434
|
+
|
|
435
|
+
```html
|
|
436
|
+
<!-- Light Theme -->
|
|
437
|
+
<nlabs-data-grid [theme]="'light'" />
|
|
438
|
+
|
|
439
|
+
<!-- Dark Theme -->
|
|
440
|
+
<nlabs-data-grid [theme]="'dark'" />
|
|
441
|
+
|
|
442
|
+
<!-- With Theme Selector -->
|
|
443
|
+
<nlabs-data-grid
|
|
444
|
+
[theme]="'dark'"
|
|
445
|
+
[showThemeSelector]="true"
|
|
446
|
+
/>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## Configuration Options
|
|
450
|
+
|
|
451
|
+
### GridConfig Interface
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
interface GridConfig {
|
|
455
|
+
// Column definitions
|
|
456
|
+
columns: GridColumn[];
|
|
457
|
+
|
|
458
|
+
// Pagination
|
|
459
|
+
pageSize?: number;
|
|
460
|
+
pageSizeOptions?: number[];
|
|
461
|
+
|
|
462
|
+
// Features
|
|
463
|
+
sortable?: boolean;
|
|
464
|
+
filterable?: boolean;
|
|
465
|
+
selectable?: boolean;
|
|
466
|
+
multiSelect?: boolean;
|
|
467
|
+
resizable?: boolean;
|
|
468
|
+
reorderable?: boolean;
|
|
469
|
+
|
|
470
|
+
// Checkbox column
|
|
471
|
+
showCheckboxColumn?: boolean;
|
|
472
|
+
checkboxColumnWidth?: string;
|
|
473
|
+
|
|
474
|
+
// Actions column
|
|
475
|
+
showActions?: boolean;
|
|
476
|
+
actionsHeader?: string;
|
|
477
|
+
actionsWidth?: string;
|
|
478
|
+
|
|
479
|
+
// UI
|
|
480
|
+
showHeader?: boolean;
|
|
481
|
+
showFooter?: boolean;
|
|
482
|
+
emptyMessage?: string;
|
|
483
|
+
rowHeight?: string;
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### GridColumn Interface
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
interface GridColumn {
|
|
491
|
+
field: string;
|
|
492
|
+
header: string;
|
|
493
|
+
type?: 'string' | 'number' | 'boolean' | 'date';
|
|
494
|
+
width?: string;
|
|
495
|
+
minWidth?: string;
|
|
496
|
+
maxWidth?: string;
|
|
497
|
+
sortable?: boolean;
|
|
498
|
+
filterable?: boolean;
|
|
499
|
+
resizable?: boolean;
|
|
500
|
+
visible?: boolean;
|
|
501
|
+
format?: (value: any) => string;
|
|
502
|
+
cellTemplate?: TemplateRef<any>;
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## Input Properties
|
|
507
|
+
|
|
508
|
+
| Property | Type | Default | Description |
|
|
509
|
+
|----------|------|---------|-------------|
|
|
510
|
+
| `config` | `GridConfig` | - | Grid configuration object |
|
|
511
|
+
| `adapter` | `IDataAdapter` | - | Data adapter (OData, Mock, etc.) |
|
|
512
|
+
| `data` | `T[]` | `[]` | Static data array |
|
|
513
|
+
| `totalRecords` | `number` | `0` | Total record count for pagination |
|
|
514
|
+
| `autoLoad` | `boolean` | `true` | Auto-load data on init |
|
|
515
|
+
| `lazy` | `boolean` | `true` | Enable lazy loading |
|
|
516
|
+
| `theme` | `'light' \| 'dark'` | `'light'` | Theme mode |
|
|
517
|
+
| `showThemeSelector` | `boolean` | `false` | Show theme toggle button |
|
|
518
|
+
| `showColumnChooser` | `boolean` | `true` | Show column visibility selector |
|
|
519
|
+
| `showGlobalSearch` | `boolean` | `false` | Show global search input |
|
|
520
|
+
| `showAddButton` | `boolean` | `false` | Show add new button |
|
|
521
|
+
| `addButtonText` | `string` | `'Add New'` | Add button text |
|
|
522
|
+
| `showExport` | `boolean` | `false` | Show export buttons |
|
|
523
|
+
| `exportFileName` | `string` | `'export'` | Export file name |
|
|
524
|
+
| `showFooter` | `boolean` | `true` | Show grid footer |
|
|
525
|
+
|
|
526
|
+
## Output Events
|
|
527
|
+
|
|
528
|
+
| Event | Payload | Description |
|
|
529
|
+
|-------|---------|-------------|
|
|
530
|
+
| `dataLoad` | `GridDataResult<T>` | Fired when data is loaded |
|
|
531
|
+
| `rowSelect` | `T` | Fired when a row is selected |
|
|
532
|
+
| `rowUnselect` | `T` | Fired when a row is unselected |
|
|
533
|
+
| `stateChange` | `GridState` | Fired when grid state changes |
|
|
534
|
+
| `addClick` | `void` | Fired when add button is clicked |
|
|
535
|
+
| `excelExport` | `T[]` | Fired when Excel export is requested |
|
|
536
|
+
| `pdfExport` | `T[]` | Fired when PDF export is requested |
|
|
537
|
+
|
|
538
|
+
## Styling
|
|
539
|
+
|
|
540
|
+
### CSS Variables
|
|
541
|
+
|
|
542
|
+
The grid uses CSS variables for theming. You can customize colors by overriding these variables:
|
|
543
|
+
|
|
544
|
+
```css
|
|
545
|
+
:root {
|
|
546
|
+
--grid-primary-color: #4096ff;
|
|
547
|
+
--grid-primary-hover: #1677ff;
|
|
548
|
+
--grid-bg-primary: #ffffff;
|
|
549
|
+
--grid-bg-secondary: #f5f7fa;
|
|
550
|
+
--grid-bg-hover: #f5f9ff;
|
|
551
|
+
--grid-text-primary: #262626;
|
|
552
|
+
--grid-text-secondary: #666666;
|
|
553
|
+
--grid-border-color: #d9d9d9;
|
|
554
|
+
--grid-border-dark: #bfbfbf;
|
|
555
|
+
--grid-radius-sm: 4px;
|
|
556
|
+
--grid-radius-md: 6px;
|
|
557
|
+
--grid-radius-lg: 8px;
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Dark Theme Variables
|
|
562
|
+
|
|
563
|
+
```css
|
|
564
|
+
[data-theme='dark'] {
|
|
565
|
+
--grid-bg-primary: #1f1f1f;
|
|
566
|
+
--grid-bg-secondary: #141414;
|
|
567
|
+
--grid-bg-hover: #2a2a2a;
|
|
568
|
+
--grid-text-primary: #e0e0e0;
|
|
569
|
+
--grid-text-secondary: #a0a0a0;
|
|
570
|
+
--grid-border-color: #404040;
|
|
571
|
+
--grid-border-dark: #4a4a4a;
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Custom Button Styles
|
|
576
|
+
|
|
577
|
+
```css
|
|
578
|
+
.btn-edit {
|
|
579
|
+
color: var(--grid-primary-color, #4096ff);
|
|
580
|
+
border: 1px solid var(--grid-primary-color, #4096ff);
|
|
581
|
+
background: var(--grid-bg-primary, #fff);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.btn-delete {
|
|
585
|
+
color: #ef4444;
|
|
586
|
+
border: 1px solid #ef4444;
|
|
587
|
+
background: var(--grid-bg-primary, #fff);
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Browser Support
|
|
592
|
+
|
|
593
|
+
- Chrome (latest)
|
|
594
|
+
- Firefox (latest)
|
|
595
|
+
- Safari (latest)
|
|
596
|
+
- Edge (latest)
|
|
597
|
+
|
|
598
|
+
## Requirements
|
|
599
|
+
|
|
600
|
+
- Angular 21+
|
|
601
|
+
- TypeScript 5.9+
|
|
602
|
+
- RxJS 7.8+
|
|
603
|
+
|
|
604
|
+
## Building the Library
|
|
605
|
+
|
|
606
|
+
```bash
|
|
607
|
+
# Build the library
|
|
608
|
+
ng build nlabs-grid
|
|
609
|
+
|
|
610
|
+
# Watch mode
|
|
611
|
+
ng build nlabs-grid --watch
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## Publishing
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
# Navigate to dist folder
|
|
618
|
+
cd dist/nlabs-grid
|
|
619
|
+
|
|
620
|
+
# Publish to npm
|
|
621
|
+
npm publish
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
## License
|
|
625
|
+
|
|
626
|
+
MIT License
|
|
627
|
+
|
|
628
|
+
## Author
|
|
629
|
+
|
|
630
|
+
nLabs Development Team
|
|
631
|
+
|
|
632
|
+
## Contributing
|
|
633
|
+
|
|
634
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
635
|
+
|
|
636
|
+
## Support
|
|
637
|
+
|
|
638
|
+
For issues and questions, please use the GitHub issue tracker.
|