@memberjunction/ng-list-detail-grid 4.0.0 → 4.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.
Files changed (2) hide show
  1. package/README.md +59 -419
  2. package/package.json +7 -7
package/README.md CHANGED
@@ -1,42 +1,34 @@
1
1
  # @memberjunction/ng-list-detail-grid
2
2
 
3
- The `@memberjunction/ng-list-detail-grid` package provides a powerful Angular grid component for displaying and managing list details in the MemberJunction Explorer application. It enables users to view, edit, compare, merge, and export records from any MemberJunction entity with comprehensive data management capabilities.
3
+ Angular grid component for displaying records belonging to a MemberJunction List. Wraps the `mj-entity-data-grid` component with automatic list-based filtering using subquery SQL filters.
4
4
 
5
- ## Features
5
+ ## Overview
6
6
 
7
- - **Data Display & Navigation**
8
- - Display records from both saved views and dynamic queries
9
- - Virtual scrolling with pagination for optimal performance
10
- - Automatic column formatting based on entity metadata
11
- - Support for boolean values with checkmark display
12
- - Configurable bottom margin for layout flexibility
7
+ The `ListDetailGridComponent` takes a `listId` and loads the associated `ListEntity` to determine the target entity and build a SQL subquery filter that fetches only records whose IDs appear in the list's detail records. It supports auto-navigation to records on click, selection events, and dynamic list switching.
13
8
 
14
- - **Editing Capabilities**
15
- - Inline cell editing with validation
16
- - Three edit modes: None, Save (immediate), and Queue (batch)
17
- - Keyboard navigation support (ESC to cancel edits)
18
- - Automatic data type detection for appropriate editors
19
- - Revert pending changes functionality
9
+ ```mermaid
10
+ graph TD
11
+ LDG["ListDetailGridComponent\n(<mj-list-detail-grid>)"] --> LE["ListEntity\n(List metadata)"]
12
+ LDG --> EDG["EntityDataGridComponent\n(<mj-entity-data-grid>)"]
13
+ EDG --> KG["Kendo Grid"]
14
+ LE --> SF["SQL Subquery Filter\n(ListDetail records)"]
20
15
 
21
- - **Column Management**
22
- - Column reordering via drag and drop
23
- - Column resizing with persistence
24
- - Multi-column sorting
25
- - Hide/show columns
26
- - Automatic column width based on entity metadata
16
+ style LDG fill:#7c5295,stroke:#563a6b,color:#fff
17
+ style LE fill:#2d6a9f,stroke:#1a4971,color:#fff
18
+ style EDG fill:#2d8659,stroke:#1a5c3a,color:#fff
19
+ style KG fill:#b8762f,stroke:#8a5722,color:#fff
20
+ style SF fill:#b8762f,stroke:#8a5722,color:#fff
21
+ ```
27
22
 
28
- - **Record Operations**
29
- - Compare multiple records side-by-side
30
- - Merge duplicate records with field-level selection
31
- - Find potential duplicates within datasets
32
- - Multi-record selection with checkbox mode
33
- - Excel export with full dataset support
23
+ ## Features
34
24
 
35
- - **Integration Features**
36
- - Deep integration with MemberJunction metadata system
37
- - Automatic permission checking for CRUD operations
38
- - State persistence for saved views
39
- - Event-driven architecture for parent component interaction
25
+ - **List-based filtering**: Automatically builds SQL subquery filter from ListDetail records
26
+ - **Auto-navigation**: Optionally navigates to entity record on row click
27
+ - **Row click events**: Emits `ListGridRowClickedEvent` with entity info and composite key
28
+ - **Dynamic list switching**: Reloads when `listId` input changes
29
+ - **Toolbar integration**: Configurable grid toolbar via `GridToolbarConfig`
30
+ - **Selection modes**: Supports single and multi-row selection
31
+ - **Loading state**: Shows loading indicator via `<mj-loading>` while list data loads
40
32
 
41
33
  ## Installation
42
34
 
@@ -44,416 +36,64 @@ The `@memberjunction/ng-list-detail-grid` package provides a powerful Angular gr
44
36
  npm install @memberjunction/ng-list-detail-grid
45
37
  ```
46
38
 
47
- ## Requirements
39
+ ## Key Dependencies
48
40
 
49
- - Angular 21+
50
- - @memberjunction/core
51
- - @memberjunction/core-entities
52
- - @memberjunction/ng-compare-records
53
- - @memberjunction/ng-container-directives
54
- - @progress/kendo-angular-grid
55
- - @progress/kendo-angular-layout
56
- - @progress/kendo-angular-inputs
57
- - @progress/kendo-angular-buttons
41
+ | Dependency | Purpose |
42
+ |---|---|
43
+ | `@memberjunction/core` | Metadata, RunView, CompositeKey |
44
+ | `@memberjunction/core-entities` | ListEntity |
45
+ | `@memberjunction/ng-entity-viewer` | EntityDataGridComponent |
46
+ | `@memberjunction/ng-shared` | SharedService, navigation |
47
+ | `@memberjunction/ng-shared-generic` | Loading indicator |
58
48
 
59
49
  ## Usage
60
50
 
61
- ### Basic Setup
62
-
63
- First, import the ListDetailGridModule in your module:
64
-
65
- ```typescript
66
- import { ListDetailGridModule } from '@memberjunction/ng-list-detail-grid';
67
-
68
- @NgModule({
69
- imports: [
70
- // other imports...
71
- ListDetailGridModule
72
- ],
73
- })
74
- export class YourModule { }
75
- ```
76
-
77
- ### Basic Usage
78
-
79
- Use the component in your template:
80
-
81
- ```html
82
- <mj-list-detail-grid
83
- [Params]="viewParams"
84
- [AutoNavigate]="true"
85
- (rowClicked)="onRowClicked($event)"
86
- (rowEdited)="onRowEdited($event)">
87
- </mj-list-detail-grid>
88
- ```
89
-
90
- In your component:
91
-
92
- ```typescript
93
- import { Component } from '@angular/core';
94
- import { RunViewParams } from '@memberjunction/core';
95
- import { GridRowClickedEvent, GridRowEditedEvent } from '@memberjunction/ng-list-detail-grid';
96
-
97
- @Component({
98
- selector: 'app-my-list-view',
99
- templateUrl: './my-list-view.component.html',
100
- })
101
- export class MyListViewComponent {
102
- viewParams: RunViewParams = {
103
- EntityName: 'Lists',
104
- ExtraFilter: "Name LIKE '%Customer%'",
105
- Skip: 0,
106
- Take: 40
107
- };
108
-
109
- onRowClicked(event: GridRowClickedEvent) {
110
- console.log('Row clicked:', event);
111
- // Access event.entityName, event.entityId, event.CompositeKey
112
- }
113
-
114
- onRowEdited(event: GridRowEditedEvent) {
115
- console.log('Row edited:', event);
116
- // Access event.record, event.row, event.saved
117
- }
118
- }
119
- ```
120
-
121
- ### Editing Mode
122
-
123
- Enable inline editing in the grid:
124
-
125
51
  ```html
126
52
  <mj-list-detail-grid
127
- [Params]="viewParams"
128
- [InEditMode]="false"
129
- [EditMode]="'Save'"
130
- (rowEdited)="onRowEdited($event)">
53
+ [listId]="selectedList.ID"
54
+ [autoNavigate]="true"
55
+ (rowClicked)="onRecordSelected($event)">
131
56
  </mj-list-detail-grid>
132
57
  ```
133
58
 
134
- The `EditMode` property supports three values:
135
- - `"None"` - Editing is disabled
136
- - `"Save"` - Changes are saved immediately
137
- - `"Queue"` - Changes are queued for later saving
138
-
139
- ### Record Operations
140
-
141
- The grid supports comparing, merging, and finding duplicates:
142
-
143
- ```typescript
144
- // In your component
145
- import { ViewChild } from '@angular/core';
146
- import { ListDetailGridComponent } from '@memberjunction/ng-list-detail-grid';
147
-
148
- @Component({
149
- // ...
150
- })
151
- export class MyListViewComponent {
152
- @ViewChild(ListDetailGridComponent) listDetailGrid!: ListDetailGridComponent;
153
-
154
- // Start compare mode
155
- startCompare() {
156
- this.listDetailGrid.enableCheckbox(false, 'compare');
157
- }
158
-
159
- // Start merge mode
160
- startMerge() {
161
- this.listDetailGrid.enableCheckbox(false, 'merge');
162
- }
163
-
164
- // Start duplicate detection
165
- findDuplicates() {
166
- this.listDetailGrid.enableCheckbox(false, 'duplicate');
167
- }
168
- }
169
- ```
170
-
171
- ## API Reference
172
-
173
- ### ListDetailGridComponent
174
-
175
- The main component that renders the grid and handles all data operations.
176
-
177
- #### Inputs
178
-
179
- | Name | Type | Default | Description |
180
- |------|------|---------|-------------|
181
- | `Params` | `RunViewParams` | `undefined` | Parameters for the view to display. Can include ViewID, ViewName, ViewEntity, or EntityName with ExtraFilter |
182
- | `BottomMargin` | `number` | `0` | Margin to apply at the bottom of the grid in pixels |
183
- | `InEditMode` | `boolean` | `false` | Whether the grid is currently in edit mode |
184
- | `EditMode` | `"None" \| "Save" \| "Queue"` | `"None"` | Mode for handling edited records. "Save" saves immediately, "Queue" batches changes |
185
- | `AutoNavigate` | `boolean` | `true` | Whether to auto-navigate to a record detail page when clicked |
186
- | `AllowLoad` | `boolean` | `true` | Whether to allow loading the data. Useful for deferring load until ready |
187
-
188
- #### Outputs
189
-
190
- | Name | Type | Description |
191
- |------|------|-------------|
192
- | `rowClicked` | `EventEmitter<GridRowClickedEvent>` | Emitted when a row is clicked, includes entity info and composite key |
193
- | `rowEdited` | `EventEmitter<GridRowEditedEvent>` | Emitted when a row is edited, includes the record and save status |
194
-
195
- #### Public Methods
196
-
197
- | Name | Parameters | Return Type | Description |
198
- |------|------------|-------------|-------------|
199
- | `Refresh` | `params: RunViewParams` | `Promise<void>` | Refreshes the grid data with new parameters |
200
- | `RefreshFromSavedParams` | None | `Promise<void>` | Refreshes using the current saved parameters |
201
- | `EditingComplete` | None | `Promise<boolean>` | Completes the current edit operation and closes any open cells |
202
- | `RevertPendingChanges` | None | `void` | Reverts all pending changes in Queue mode |
203
- | `enableCheckbox` | `cancel: boolean, type: 'merge' \| 'compare' \| 'duplicate' \| ''` | `void` | Enables/disables selection mode for operations |
204
- | `doExcelExport` | None | `Promise<void>` | Exports the entire dataset to Excel |
205
- | `IsDynamicView` | None | `boolean` | Returns true if using a dynamic view (not saved) |
206
-
207
- #### Public Properties
208
-
209
- | Name | Type | Description |
210
- |------|------|-------------|
211
- | `PendingRecords` | `GridPendingRecordItem[]` | Array of records with pending changes in Queue mode |
212
- | `ViewID` | `string` | The ID of the current view (if using a saved view) |
213
- | `viewColumns` | `ViewColumnInfo[]` | Array of all column configurations |
214
- | `visibleColumns` | `ViewColumnInfo[]` | Array of visible (non-hidden) columns |
215
- | `viewExecutionTime` | `number` | Time taken to execute the view query (in seconds) |
216
-
217
- ### Type Definitions
218
-
219
- #### GridRowClickedEvent
220
-
221
- Emitted when a user clicks on a grid row.
222
-
223
- ```typescript
224
- type GridRowClickedEvent = {
225
- entityId: string; // The ID of the entity definition
226
- entityName: string; // The name of the entity
227
- CompositeKey: CompositeKey; // Composite key object for the clicked record
228
- }
229
- ```
230
-
231
- #### GridRowEditedEvent
232
-
233
- Emitted when a row edit operation completes.
234
-
235
- ```typescript
236
- type GridRowEditedEvent = {
237
- record: BaseEntity; // The entity record that was edited
238
- row: number; // The row index in the grid
239
- saved: boolean; // Whether the save was successful (always false in Queue mode)
240
- }
241
- ```
242
-
243
- #### GridPendingRecordItem
59
+ ### Inputs
244
60
 
245
- Represents a record with pending changes in Queue mode.
61
+ | Input | Type | Default | Description |
62
+ |---|---|---|---|
63
+ | `listId` | `string` | Required | The List ID to display records for |
64
+ | `autoNavigate` | `boolean` | `false` | Navigate to record on row click |
246
65
 
247
- ```typescript
248
- type GridPendingRecordItem = {
249
- record: BaseEntity; // The entity record with changes
250
- row: number; // The row index in the grid
251
- dataItem: any; // The raw data item from the grid
252
- }
253
- ```
66
+ ### Outputs
254
67
 
255
- ## Customization
68
+ | Output | Type | Description |
69
+ |---|---|---|
70
+ | `rowClicked` | `EventEmitter<ListGridRowClickedEvent>` | Emitted when a row is clicked |
256
71
 
257
- ### Column Customization
258
-
259
- The grid automatically formats columns based on entity metadata, but you can customize the formatting by modifying the view columns:
72
+ ### ListGridRowClickedEvent
260
73
 
261
74
  ```typescript
262
- // In your component
263
- modifyColumns() {
264
- const columns = this.listDetailGrid.viewColumns;
265
- // Customize columns here
266
- columns.forEach(col => {
267
- if (col.Name === 'Priority') {
268
- col.width = 80;
269
- }
270
- });
271
- this.listDetailGrid.Refresh(this.listDetailGrid.Params!);
75
+ interface ListGridRowClickedEvent {
76
+ entityId: string;
77
+ entityName: string;
78
+ compositeKey: CompositeKey;
79
+ record: BaseEntity;
272
80
  }
273
81
  ```
274
82
 
275
- ### Advanced Usage
276
-
277
- #### Working with Dynamic Views
278
-
279
- For scenarios where you need to display data without a saved view:
280
-
281
- ```typescript
282
- // Dynamic view with custom filtering
283
- const dynamicParams: RunViewParams = {
284
- EntityName: 'Customers',
285
- ExtraFilter: "Status='Active' AND Country='USA'",
286
- OrderBy: 'CreatedAt DESC',
287
- Skip: 0,
288
- Take: 100
289
- };
290
-
291
- // Use with the grid
292
- <mj-list-detail-grid [Params]="dynamicParams"></mj-list-detail-grid>
293
- ```
294
-
295
- #### Handling Batch Edits
83
+ ## Exported API
296
84
 
297
- When using Queue mode for batch editing:
85
+ | Export | Type | Description |
86
+ |---|---|---|
87
+ | `ListDetailGridComponent` | Component | List-filtered data grid |
88
+ | `ListGridRowClickedEvent` | Interface | Row click event type |
89
+ | `ListDetailGridModule` | NgModule | Module declaration |
298
90
 
299
- ```typescript
300
- export class MyComponent {
301
- @ViewChild(ListDetailGridComponent) grid!: ListDetailGridComponent;
302
-
303
- async savePendingChanges() {
304
- // Get all pending records
305
- const pendingRecords = this.grid.PendingRecords;
306
-
307
- // Save each record
308
- for (const item of pendingRecords) {
309
- const saved = await item.record.Save();
310
- if (!saved) {
311
- console.error('Failed to save record:', item.record.PrimaryKey);
312
- }
313
- }
314
-
315
- // Refresh the grid
316
- await this.grid.RefreshFromSavedParams();
317
- }
318
-
319
- cancelChanges() {
320
- this.grid.RevertPendingChanges();
321
- }
322
- }
323
- ```
324
-
325
- #### Programmatic Record Operations
91
+ ## Build
326
92
 
327
- ```typescript
328
- export class MyComponent {
329
- @ViewChild(ListDetailGridComponent) grid!: ListDetailGridComponent;
330
-
331
- // Start duplicate detection
332
- async detectDuplicates() {
333
- // Enable duplicate mode
334
- this.grid.enableCheckbox(false, 'duplicate');
335
-
336
- // Programmatically select records if needed
337
- this.grid.selectedKeys = [0, 1, 2]; // Select first 3 records
338
-
339
- // Trigger duplicate detection
340
- await this.grid.findDuplicateRecords();
341
- }
342
- }
93
+ ```bash
94
+ cd packages/Angular/Explorer/list-detail-grid && npm run build
343
95
  ```
344
96
 
345
- ### Performance Optimization
346
-
347
- The grid implements several performance optimizations:
348
-
349
- 1. **Virtual Scrolling**: Only renders visible rows, enabling smooth scrolling through large datasets
350
- 2. **Lazy Column Formatting**: Formats data only when needed for display
351
- 3. **Debounced View Saving**: Column and sort changes are saved after a 5-second delay to reduce API calls
352
- 4. **Efficient Data Loading**: Uses MemberJunction's RunView for optimized server-side queries
353
-
354
- ### Styling
355
-
356
- The component uses the following CSS classes that can be customized:
357
-
358
- - `.list-detail-grid-wrap`: Main container for the grid
359
- - Column-specific styles are applied based on data types (right-aligned for numbers, left-aligned for text)
360
-
361
- ### Best Practices
362
-
363
- 1. **Use Saved Views When Possible**: Saved views persist user preferences and are more performant
364
- 2. **Choose Appropriate Edit Mode**:
365
- - Use "Save" mode for immediate persistence
366
- - Use "Queue" mode when users need to review changes before saving
367
- 3. **Handle Events Properly**: Always handle `rowEdited` events to provide user feedback
368
- 4. **Export Considerations**: Large exports may take time; the component shows notifications during export
369
- 5. **Permission Checking**: The component automatically checks entity permissions before allowing edits
370
-
371
- ## Integration with MemberJunction
372
-
373
- This component deeply integrates with MemberJunction's metadata system:
374
-
375
- - Automatically formats columns based on entity field metadata
376
- - Respects entity permissions for CRUD operations
377
- - Uses entity field validation rules
378
- - Supports all MemberJunction field types including virtual fields
379
- - Integrates with the MemberJunction audit log for exports
380
-
381
- ## Dependencies
382
-
383
- ### Angular Dependencies
384
- - `@angular/common`: ^18.0.2
385
- - `@angular/core`: ^18.0.2
386
- - `@angular/forms`: ^18.0.2
387
- - `@angular/router`: ^18.0.2
388
-
389
- ### MemberJunction Dependencies
390
- - `@memberjunction/core`: ^2.43.0
391
- - `@memberjunction/core-entities`: ^2.43.0
392
- - `@memberjunction/global`: ^2.43.0
393
- - `@memberjunction/ng-shared`: ^2.43.0
394
- - `@memberjunction/ng-compare-records`: ^2.43.0
395
- - `@memberjunction/ng-container-directives`: ^2.43.0
396
-
397
- ### Kendo UI Dependencies
398
- - `@progress/kendo-angular-grid`: ^16.2.0
399
- - `@progress/kendo-angular-layout`: ^16.2.0
400
- - `@progress/kendo-angular-inputs`: ^16.2.0
401
- - `@progress/kendo-angular-buttons`: ^16.2.0
402
- - `@progress/kendo-angular-excel-export`: (via GridModule)
403
- - `@progress/kendo-angular-dialog`: (via GridModule)
404
-
405
- ## Troubleshooting
406
-
407
- ### Common Issues
408
-
409
- #### Grid Not Loading Data
410
- - Ensure `AllowLoad` is set to `true` (default)
411
- - Verify that `Params` contains valid view parameters
412
- - Check console for API errors or permission issues
413
-
414
- #### Edit Mode Not Working
415
- - Verify the entity has `AllowUpdateAPI` set to true
416
- - Check user permissions for the entity
417
- - Ensure `EditMode` is set to either "Save" or "Queue"
418
-
419
- #### Export Failing
420
- - Check for large dataset timeouts
421
- - Ensure user has appropriate permissions
422
- - Verify the export audit log entry was created
423
-
424
- #### Column Reordering Not Persisting
425
- - Only works with saved views (not dynamic views)
426
- - User must own the view to save changes
427
- - Check for save errors in the console
428
-
429
- ### Debug Tips
430
-
431
- 1. Enable console logging to see detailed error messages
432
- 2. Check the Network tab for failed API calls
433
- 3. Verify entity metadata is loaded before grid initialization
434
- 4. Use `viewExecutionTime` property to identify slow queries
435
-
436
- ## Migration Guide
437
-
438
- ### From Earlier Versions
439
-
440
- If upgrading from versions prior to 2.43.0:
441
-
442
- 1. Update all MemberJunction dependencies to matching versions
443
- 2. Update Angular to version 18
444
- 3. Update Kendo UI components to version 16.2.0
445
- 4. Review breaking changes in the CHANGELOG.md
446
-
447
- ## Contributing
448
-
449
- When contributing to this package:
450
-
451
- 1. Follow the MemberJunction coding standards
452
- 2. Ensure all TypeScript compiles without errors
453
- 3. Update this README for any API changes
454
- 4. Add unit tests for new functionality
455
- 5. Update the CHANGELOG.md
456
-
457
97
  ## License
458
98
 
459
- This package is part of the MemberJunction framework and follows the same [ISC License](../../../LICENSE).
99
+ ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-list-detail-grid",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "MemberJunction: Angular Grid to display dynamic and saved List Details for any entity in MemberJunction.",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -25,12 +25,12 @@
25
25
  "@angular/router": "21.1.3"
26
26
  },
27
27
  "dependencies": {
28
- "@memberjunction/core": "4.0.0",
29
- "@memberjunction/core-entities": "4.0.0",
30
- "@memberjunction/global": "4.0.0",
31
- "@memberjunction/ng-entity-viewer": "4.0.0",
32
- "@memberjunction/ng-shared": "4.0.0",
33
- "@memberjunction/ng-shared-generic": "4.0.0",
28
+ "@memberjunction/core": "4.1.0",
29
+ "@memberjunction/core-entities": "4.1.0",
30
+ "@memberjunction/global": "4.1.0",
31
+ "@memberjunction/ng-entity-viewer": "4.1.0",
32
+ "@memberjunction/ng-shared": "4.1.0",
33
+ "@memberjunction/ng-shared-generic": "4.1.0",
34
34
  "rxjs": "~7.8.2",
35
35
  "tslib": "^2.8.1"
36
36
  },