@memberjunction/ng-query-grid 2.43.0 → 2.44.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 +246 -116
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @memberjunction/ng-query-grid
|
|
2
2
|
|
|
3
|
-
An Angular
|
|
3
|
+
An Angular component for displaying and interacting with data from any MemberJunction query. This component provides a flexible, feature-rich grid interface with built-in pagination, sorting, Excel export capabilities, and more.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Query Grid component is designed to seamlessly display results from MemberJunction queries in a highly configurable Kendo UI Grid. It handles all the complexity of data loading, pagination, and user interactions while providing a clean API for developers to integrate query results into their Angular applications.
|
|
4
8
|
|
|
5
9
|
## Features
|
|
6
10
|
|
|
7
|
-
- **Query-Based Data Display**:
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **Excel Export**: One-click export to Excel
|
|
11
|
+
- **Query-Based Data Display**: Execute and display results from any MemberJunction query
|
|
12
|
+
- **Virtual Scrolling**: Efficient handling of large datasets with virtual scrolling
|
|
13
|
+
- **Pagination**: Built-in pagination with configurable page size (default: 40 rows)
|
|
14
|
+
- **Excel Export**: One-click export to Excel with automatic filename generation
|
|
11
15
|
- **Sorting and Reordering**: Sort columns and reorder them via drag and drop
|
|
16
|
+
- **Column Resizing**: Resize columns to fit your data
|
|
12
17
|
- **Row Selection**: Select rows for further operations
|
|
13
|
-
- **
|
|
14
|
-
- **Event Handling**: Row click events for interactive applications
|
|
18
|
+
- **Row Click Events**: Handle row clicks with detailed event data
|
|
15
19
|
- **Loading States**: Visual feedback during data fetching
|
|
20
|
+
- **Responsive Layout**: Automatically fills container with `mjFillContainer` directive
|
|
21
|
+
- **Refresh Capability**: Built-in refresh button to reload data
|
|
22
|
+
- **Deferred Loading**: Control when data loads with the `AllowLoad` input
|
|
16
23
|
|
|
17
24
|
## Installation
|
|
18
25
|
|
|
@@ -47,119 +54,177 @@ export class YourModule { }
|
|
|
47
54
|
</mj-query-grid>
|
|
48
55
|
```
|
|
49
56
|
|
|
50
|
-
###
|
|
57
|
+
### Advanced Configuration
|
|
51
58
|
|
|
52
59
|
```html
|
|
53
|
-
<!--
|
|
60
|
+
<!-- Fully configured query grid -->
|
|
54
61
|
<mj-query-grid
|
|
55
62
|
[Params]="queryParams"
|
|
56
63
|
[BottomMargin]="20"
|
|
57
64
|
[AutoNavigate]="false"
|
|
58
|
-
[AllowLoad]="
|
|
59
|
-
|
|
65
|
+
[AllowLoad]="isReadyToLoad"
|
|
66
|
+
[InEditMode]="false"
|
|
67
|
+
[EditMode]="'None'"
|
|
68
|
+
(rowClicked)="handleRowClick($event)">
|
|
60
69
|
</mj-query-grid>
|
|
61
70
|
```
|
|
62
71
|
|
|
63
|
-
### TypeScript
|
|
72
|
+
### Complete TypeScript Example
|
|
64
73
|
|
|
65
74
|
```typescript
|
|
66
|
-
import { Component, OnInit } from '@angular/core';
|
|
75
|
+
import { Component, OnInit, ViewChild } from '@angular/core';
|
|
67
76
|
import { RunQueryParams } from '@memberjunction/core';
|
|
68
|
-
import { GridRowClickedEvent } from '@memberjunction/ng-query-grid';
|
|
77
|
+
import { GridRowClickedEvent, QueryGridComponent } from '@memberjunction/ng-query-grid';
|
|
69
78
|
|
|
70
79
|
@Component({
|
|
71
|
-
selector: 'app-
|
|
80
|
+
selector: 'app-customer-orders',
|
|
72
81
|
template: `
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
</
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
<div class="orders-container">
|
|
83
|
+
<h2>Customer Orders</h2>
|
|
84
|
+
|
|
85
|
+
<div class="controls">
|
|
86
|
+
<button kendoButton (click)="refreshData()">
|
|
87
|
+
<span class="fa-solid fa-refresh"></span> Refresh
|
|
88
|
+
</button>
|
|
89
|
+
|
|
90
|
+
<label>
|
|
91
|
+
Date Range:
|
|
92
|
+
<input type="date" [(ngModel)]="startDate" (change)="updateQueryParams()">
|
|
93
|
+
to
|
|
94
|
+
<input type="date" [(ngModel)]="endDate" (change)="updateQueryParams()">
|
|
95
|
+
</label>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div class="grid-container" style="height: 600px;">
|
|
99
|
+
<mj-query-grid
|
|
100
|
+
#orderGrid
|
|
101
|
+
[Params]="orderQueryParams"
|
|
102
|
+
[AutoNavigate]="false"
|
|
103
|
+
[AllowLoad]="true"
|
|
104
|
+
(rowClicked)="onOrderRowClicked($event)">
|
|
105
|
+
</mj-query-grid>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div *ngIf="selectedOrder" class="order-details">
|
|
109
|
+
<h3>Selected Order Details</h3>
|
|
110
|
+
<dl>
|
|
111
|
+
<dt>Order ID:</dt>
|
|
112
|
+
<dd>{{ getOrderField('OrderID') }}</dd>
|
|
113
|
+
|
|
114
|
+
<dt>Customer:</dt>
|
|
115
|
+
<dd>{{ getOrderField('CustomerName') }}</dd>
|
|
116
|
+
|
|
117
|
+
<dt>Order Date:</dt>
|
|
118
|
+
<dd>{{ getOrderField('OrderDate') | date }}</dd>
|
|
119
|
+
|
|
120
|
+
<dt>Total Amount:</dt>
|
|
121
|
+
<dd>{{ getOrderAmount() | currency }}</dd>
|
|
122
|
+
</dl>
|
|
123
|
+
</div>
|
|
95
124
|
</div>
|
|
96
125
|
`,
|
|
97
126
|
styles: [`
|
|
98
|
-
.
|
|
99
|
-
|
|
127
|
+
.orders-container {
|
|
128
|
+
padding: 20px;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.controls {
|
|
132
|
+
margin-bottom: 20px;
|
|
133
|
+
display: flex;
|
|
134
|
+
gap: 20px;
|
|
135
|
+
align-items: center;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.grid-container {
|
|
139
|
+
border: 1px solid #ddd;
|
|
100
140
|
margin-bottom: 20px;
|
|
101
141
|
}
|
|
102
|
-
|
|
103
|
-
|
|
142
|
+
|
|
143
|
+
.order-details {
|
|
144
|
+
background: #f5f5f5;
|
|
145
|
+
padding: 20px;
|
|
146
|
+
border-radius: 4px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
dl {
|
|
150
|
+
display: grid;
|
|
151
|
+
grid-template-columns: 150px 1fr;
|
|
152
|
+
gap: 10px;
|
|
104
153
|
}
|
|
105
|
-
|
|
106
|
-
|
|
154
|
+
|
|
155
|
+
dt {
|
|
156
|
+
font-weight: bold;
|
|
107
157
|
}
|
|
108
158
|
`]
|
|
109
159
|
})
|
|
110
|
-
export class
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
160
|
+
export class CustomerOrdersComponent implements OnInit {
|
|
161
|
+
@ViewChild('orderGrid') orderGrid!: QueryGridComponent;
|
|
162
|
+
|
|
163
|
+
orderQueryParams: RunQueryParams;
|
|
164
|
+
selectedOrder: GridRowClickedEvent | null = null;
|
|
165
|
+
startDate: string;
|
|
166
|
+
endDate: string;
|
|
114
167
|
|
|
115
168
|
constructor() {
|
|
169
|
+
// Initialize dates
|
|
170
|
+
const today = new Date();
|
|
171
|
+
const lastMonth = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate());
|
|
172
|
+
|
|
173
|
+
this.startDate = lastMonth.toISOString().split('T')[0];
|
|
174
|
+
this.endDate = today.toISOString().split('T')[0];
|
|
175
|
+
|
|
116
176
|
// Initialize query parameters
|
|
117
|
-
this.
|
|
118
|
-
QueryID: 'SalesOrdersSummary',
|
|
119
|
-
Parameters: [
|
|
120
|
-
{ Name: 'StartDate', Value: '2023-01-01' },
|
|
121
|
-
{ Name: 'EndDate', Value: '2023-12-31' }
|
|
122
|
-
]
|
|
123
|
-
};
|
|
177
|
+
this.orderQueryParams = this.createQueryParams();
|
|
124
178
|
}
|
|
125
179
|
|
|
126
180
|
ngOnInit() {
|
|
127
|
-
//
|
|
181
|
+
// Component initialization
|
|
128
182
|
}
|
|
129
183
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
184
|
+
private createQueryParams(): RunQueryParams {
|
|
185
|
+
return {
|
|
186
|
+
QueryID: 'CustomerOrdersWithDetails',
|
|
187
|
+
Parameters: [
|
|
188
|
+
{ Name: 'StartDate', Value: this.startDate },
|
|
189
|
+
{ Name: 'EndDate', Value: this.endDate },
|
|
190
|
+
{ Name: 'Status', Value: 'Active' }
|
|
191
|
+
],
|
|
192
|
+
MaxRows: 1000
|
|
193
|
+
};
|
|
136
194
|
}
|
|
137
195
|
|
|
138
|
-
|
|
139
|
-
this.
|
|
196
|
+
updateQueryParams() {
|
|
197
|
+
this.orderQueryParams = this.createQueryParams();
|
|
198
|
+
// The grid will automatically refresh when params change
|
|
140
199
|
}
|
|
141
200
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
this.
|
|
145
|
-
|
|
146
|
-
// If auto-navigate is enabled, you could navigate to a detail page
|
|
147
|
-
if (this.autoNavigate) {
|
|
148
|
-
const orderId = this.getOrderId();
|
|
149
|
-
// this.router.navigate(['/orders', orderId]);
|
|
201
|
+
refreshData() {
|
|
202
|
+
// Method 1: Using ViewChild reference
|
|
203
|
+
if (this.orderGrid) {
|
|
204
|
+
this.orderGrid.RefreshFromSavedParams();
|
|
150
205
|
}
|
|
206
|
+
|
|
207
|
+
// Method 2: Update params to trigger refresh
|
|
208
|
+
// this.orderQueryParams = { ...this.createQueryParams() };
|
|
151
209
|
}
|
|
152
210
|
|
|
153
|
-
|
|
154
|
-
|
|
211
|
+
onOrderRowClicked(event: GridRowClickedEvent) {
|
|
212
|
+
console.log('Order clicked:', event);
|
|
213
|
+
this.selectedOrder = event;
|
|
214
|
+
|
|
215
|
+
// You could navigate to a detail page here
|
|
216
|
+
// this.router.navigate(['/orders', event.entityId]);
|
|
155
217
|
}
|
|
156
218
|
|
|
157
|
-
|
|
158
|
-
|
|
219
|
+
getOrderField(fieldName: string): string {
|
|
220
|
+
if (!this.selectedOrder) return '';
|
|
221
|
+
|
|
222
|
+
const field = this.selectedOrder.KeyValuePairs.find(kvp => kvp.Key === fieldName);
|
|
223
|
+
return field?.Value || '';
|
|
159
224
|
}
|
|
160
225
|
|
|
161
226
|
getOrderAmount(): number {
|
|
162
|
-
const amount = this.
|
|
227
|
+
const amount = this.getOrderField('TotalAmount');
|
|
163
228
|
return amount ? parseFloat(amount) : 0;
|
|
164
229
|
}
|
|
165
230
|
}
|
|
@@ -167,27 +232,37 @@ export class SalesDashboardComponent implements OnInit {
|
|
|
167
232
|
|
|
168
233
|
## API Reference
|
|
169
234
|
|
|
235
|
+
### Component Selector
|
|
236
|
+
`mj-query-grid`
|
|
237
|
+
|
|
170
238
|
### Inputs
|
|
171
239
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
240
|
+
| Input | Type | Default | Description |
|
|
241
|
+
|-------|------|---------|-------------|
|
|
242
|
+
| `Params` | `RunQueryParams \| undefined` | `undefined` | Query parameters for data loading |
|
|
243
|
+
| `BottomMargin` | `number` | `0` | Bottom margin in pixels |
|
|
244
|
+
| `InEditMode` | `boolean` | `false` | Whether the grid is in edit mode |
|
|
245
|
+
| `EditMode` | `"None" \| "Save" \| "Queue"` | `"None"` | Type of edit mode |
|
|
246
|
+
| `AutoNavigate` | `boolean` | `true` | Whether to auto-navigate on row click |
|
|
247
|
+
| `AllowLoad` | `boolean` | `true` | Controls whether data loading is allowed |
|
|
178
248
|
|
|
179
249
|
### Outputs
|
|
180
250
|
|
|
181
|
-
|
|
251
|
+
| Output | Type | Description |
|
|
252
|
+
|--------|------|-------------|
|
|
253
|
+
| `rowClicked` | `EventEmitter<GridRowClickedEvent>` | Emitted when a grid row is clicked |
|
|
182
254
|
|
|
183
|
-
### Methods
|
|
255
|
+
### Public Methods
|
|
184
256
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
257
|
+
| Method | Parameters | Return Type | Description |
|
|
258
|
+
|--------|------------|-------------|-------------|
|
|
259
|
+
| `Refresh` | `params: RunQueryParams` | `Promise<void>` | Refreshes grid data with new query parameters |
|
|
260
|
+
| `RefreshFromSavedParams` | none | `Promise<void>` | Refreshes grid using previously saved parameters |
|
|
261
|
+
| `doExcelExport` | none | `Promise<void>` | Exports current grid data to Excel file |
|
|
188
262
|
|
|
189
263
|
### Types
|
|
190
264
|
|
|
265
|
+
#### GridRowClickedEvent
|
|
191
266
|
```typescript
|
|
192
267
|
export type GridRowClickedEvent = {
|
|
193
268
|
entityId: number;
|
|
@@ -196,44 +271,99 @@ export type GridRowClickedEvent = {
|
|
|
196
271
|
}
|
|
197
272
|
```
|
|
198
273
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
The component accepts a `RunQueryParams` object that specifies which query to run:
|
|
202
|
-
|
|
274
|
+
#### RunQueryParams (from @memberjunction/core)
|
|
203
275
|
```typescript
|
|
204
|
-
|
|
205
|
-
QueryID:
|
|
206
|
-
Parameters
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
276
|
+
interface RunQueryParams {
|
|
277
|
+
QueryID: string; // ID of the query to execute
|
|
278
|
+
Parameters?: QueryParam[]; // Optional query parameters
|
|
279
|
+
MaxRows?: number; // Maximum rows to return
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface QueryParam {
|
|
283
|
+
Name: string;
|
|
284
|
+
Value: any;
|
|
285
|
+
}
|
|
212
286
|
```
|
|
213
287
|
|
|
214
|
-
##
|
|
288
|
+
## Grid Configuration
|
|
215
289
|
|
|
216
|
-
The component
|
|
290
|
+
The component uses Kendo UI Grid with the following configuration:
|
|
217
291
|
|
|
218
|
-
|
|
292
|
+
- **Virtual Scrolling**: Enabled for performance with large datasets
|
|
293
|
+
- **Row Height**: 36px fixed height for virtual scrolling
|
|
294
|
+
- **Page Size**: 40 rows per page
|
|
295
|
+
- **Features**: Sorting, resizing, reordering, and selection enabled
|
|
296
|
+
- **Toolbar**: Excel export and refresh buttons
|
|
219
297
|
|
|
220
|
-
|
|
298
|
+
## Excel Export
|
|
221
299
|
|
|
222
|
-
|
|
223
|
-
-
|
|
224
|
-
-
|
|
225
|
-
-
|
|
226
|
-
-
|
|
227
|
-
- Responsive design that fills its container
|
|
300
|
+
The Excel export feature:
|
|
301
|
+
- Exports all loaded data (not just visible page)
|
|
302
|
+
- Automatically names file as `{QueryID}_Query.xlsx`
|
|
303
|
+
- Shows progress notifications during export
|
|
304
|
+
- Dynamically generates columns based on query results
|
|
228
305
|
|
|
229
|
-
## Styling
|
|
306
|
+
## Styling and Layout
|
|
230
307
|
|
|
231
|
-
The component uses
|
|
308
|
+
The component uses:
|
|
309
|
+
- `mjFillContainer` directive to fill available space
|
|
310
|
+
- Kendo UI Grid default styling
|
|
311
|
+
- Font Awesome icons for buttons
|
|
312
|
+
- Customizable through CSS
|
|
232
313
|
|
|
233
314
|
## Dependencies
|
|
234
315
|
|
|
235
|
-
|
|
316
|
+
### Peer Dependencies
|
|
317
|
+
- `@angular/common`: ^18.0.2
|
|
318
|
+
- `@angular/core`: ^18.0.2
|
|
319
|
+
- `@angular/forms`: ^18.0.2
|
|
320
|
+
- `@angular/router`: ^18.0.2
|
|
321
|
+
- `@progress/kendo-angular-grid`: ^16.2.0
|
|
322
|
+
- `@progress/kendo-angular-buttons`: ^16.2.0
|
|
323
|
+
- `@progress/kendo-angular-dialog`: ^16.2.0
|
|
324
|
+
|
|
325
|
+
### Runtime Dependencies
|
|
326
|
+
- `@memberjunction/core`: For query execution and metadata
|
|
236
327
|
- `@memberjunction/core-entities`: For entity types
|
|
237
|
-
- `@memberjunction/global`: For global utilities
|
|
238
|
-
- `@
|
|
239
|
-
- `@
|
|
328
|
+
- `@memberjunction/global`: For global utilities and events
|
|
329
|
+
- `@memberjunction/ng-container-directives`: For layout directives
|
|
330
|
+
- `@memberjunction/ng-compare-records`: For record comparison
|
|
331
|
+
- `@memberjunction/ng-shared`: For shared Angular utilities
|
|
332
|
+
|
|
333
|
+
## Integration with MemberJunction
|
|
334
|
+
|
|
335
|
+
This component integrates seamlessly with the MemberJunction ecosystem:
|
|
336
|
+
|
|
337
|
+
1. **Query Execution**: Uses `RunQuery` class from `@memberjunction/core` to execute queries
|
|
338
|
+
2. **Metadata Support**: Leverages MemberJunction metadata system
|
|
339
|
+
3. **Event System**: Uses `MJGlobal` event system for notifications
|
|
340
|
+
4. **Layout Integration**: Works with MemberJunction container directives
|
|
341
|
+
|
|
342
|
+
## Best Practices
|
|
343
|
+
|
|
344
|
+
1. **Container Height**: Always wrap the component in a container with defined height for virtual scrolling
|
|
345
|
+
2. **Query Parameters**: Validate query parameters before passing to the component
|
|
346
|
+
3. **Error Handling**: The component shows error notifications automatically
|
|
347
|
+
4. **Performance**: Use `MaxRows` parameter for large datasets
|
|
348
|
+
5. **Deferred Loading**: Use `AllowLoad` input to control when data loads
|
|
349
|
+
|
|
350
|
+
## Troubleshooting
|
|
351
|
+
|
|
352
|
+
### Grid Not Displaying
|
|
353
|
+
- Ensure the parent container has a defined height
|
|
354
|
+
- Check that `Params` includes a valid `QueryID`
|
|
355
|
+
- Verify query permissions in MemberJunction
|
|
356
|
+
|
|
357
|
+
### Export Not Working
|
|
358
|
+
- Check browser permissions for file downloads
|
|
359
|
+
- Ensure data is loaded before attempting export
|
|
360
|
+
- Verify Excel export module is properly imported
|
|
361
|
+
|
|
362
|
+
### Performance Issues
|
|
363
|
+
- Use `MaxRows` to limit result set size
|
|
364
|
+
- Enable virtual scrolling (default)
|
|
365
|
+
- Consider server-side pagination for very large datasets
|
|
366
|
+
|
|
367
|
+
## License
|
|
368
|
+
|
|
369
|
+
ISC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-query-grid",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.44.0",
|
|
4
4
|
"description": "MemberJunction: Angular Grid to display any MemberJunction Query",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"@progress/kendo-angular-dialog": "16.2.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@memberjunction/core-entities": "2.
|
|
32
|
-
"@memberjunction/global": "2.
|
|
33
|
-
"@memberjunction/core": "2.
|
|
34
|
-
"@memberjunction/ng-container-directives": "2.
|
|
35
|
-
"@memberjunction/ng-compare-records": "2.
|
|
36
|
-
"@memberjunction/ng-shared": "2.
|
|
31
|
+
"@memberjunction/core-entities": "2.44.0",
|
|
32
|
+
"@memberjunction/global": "2.44.0",
|
|
33
|
+
"@memberjunction/core": "2.44.0",
|
|
34
|
+
"@memberjunction/ng-container-directives": "2.44.0",
|
|
35
|
+
"@memberjunction/ng-compare-records": "2.44.0",
|
|
36
|
+
"@memberjunction/ng-shared": "2.44.0",
|
|
37
37
|
"tslib": "^2.3.0"
|
|
38
38
|
},
|
|
39
39
|
"sideEffects": false
|