@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.
Files changed (2) hide show
  1. package/README.md +246 -116
  2. package/package.json +7 -7
package/README.md CHANGED
@@ -1,18 +1,25 @@
1
- # Query Grid Component
1
+ # @memberjunction/ng-query-grid
2
2
 
3
- An Angular grid component for displaying and interacting with data from any MemberJunction query. This component provides a flexible way to display query results in a feature-rich grid with pagination, sorting, and Excel export capabilities.
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**: Show results from any MemberJunction query
8
- - **Pagination**: Built-in pagination with configurable page size
9
- - **Virtual Scrolling**: Efficient handling of large datasets
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
- - **Responsive Layout**: Automatically adjusts to container size
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
- ### With Configuration Options
57
+ ### Advanced Configuration
51
58
 
52
59
  ```html
53
- <!-- Configured query grid -->
60
+ <!-- Fully configured query grid -->
54
61
  <mj-query-grid
55
62
  [Params]="queryParams"
56
63
  [BottomMargin]="20"
57
64
  [AutoNavigate]="false"
58
- [AllowLoad]="isAllowedToLoad"
59
- (rowClicked)="onRowClicked($event)">
65
+ [AllowLoad]="isReadyToLoad"
66
+ [InEditMode]="false"
67
+ [EditMode]="'None'"
68
+ (rowClicked)="handleRowClick($event)">
60
69
  </mj-query-grid>
61
70
  ```
62
71
 
63
- ### TypeScript Component Example
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-sales-dashboard',
80
+ selector: 'app-customer-orders',
72
81
  template: `
73
- <h2>Sales Query Results</h2>
74
-
75
- <div class="query-controls">
76
- <button kendoButton (click)="refreshData()">Refresh Data</button>
77
- <button kendoButton (click)="toggleAutoNavigate()">
78
- {{ autoNavigate ? 'Disable' : 'Enable' }} Auto Navigation
79
- </button>
80
- </div>
81
-
82
- <div class="query-container">
83
- <mj-query-grid
84
- [Params]="salesQueryParams"
85
- [AutoNavigate]="autoNavigate"
86
- (rowClicked)="onSalesRowClicked($event)">
87
- </mj-query-grid>
88
- </div>
89
-
90
- <div *ngIf="selectedRow">
91
- <h3>Selected Order Details</h3>
92
- <p>Order ID: {{ getOrderId() }}</p>
93
- <p>Customer: {{ getCustomerName() }}</p>
94
- <p>Amount: {{ getOrderAmount() | currency }}</p>
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
- .query-container {
99
- height: 600px;
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
- .query-controls {
103
- margin-bottom: 10px;
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
- button {
106
- margin-right: 10px;
154
+
155
+ dt {
156
+ font-weight: bold;
107
157
  }
108
158
  `]
109
159
  })
110
- export class SalesDashboardComponent implements OnInit {
111
- salesQueryParams: RunQueryParams;
112
- autoNavigate = true;
113
- selectedRow: GridRowClickedEvent | null = null;
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.salesQueryParams = {
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
- // Additional initialization if needed
181
+ // Component initialization
128
182
  }
129
183
 
130
- refreshData() {
131
- // Get a reference to the grid and refresh it
132
- const grid = document.querySelector('mj-query-grid') as any;
133
- if (grid) {
134
- grid.RefreshFromSavedParams();
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
- toggleAutoNavigate() {
139
- this.autoNavigate = !this.autoNavigate;
196
+ updateQueryParams() {
197
+ this.orderQueryParams = this.createQueryParams();
198
+ // The grid will automatically refresh when params change
140
199
  }
141
200
 
142
- onSalesRowClicked(event: GridRowClickedEvent) {
143
- console.log('Row clicked:', event);
144
- this.selectedRow = event;
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
- getOrderId(): string {
154
- return this.selectedRow?.KeyValuePairs.find(kvp => kvp.Key === 'OrderID')?.Value || '';
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
- getCustomerName(): string {
158
- return this.selectedRow?.KeyValuePairs.find(kvp => kvp.Key === 'CustomerName')?.Value || '';
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.selectedRow?.KeyValuePairs.find(kvp => kvp.Key === 'TotalAmount')?.Value;
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
- - `Params`: RunQueryParams - Parameters for running the query
173
- - `BottomMargin`: number - Bottom margin in pixels (default: 0)
174
- - `InEditMode`: boolean - Whether the grid is in edit mode (default: false)
175
- - `EditMode`: "None" | "Save" | "Queue" - Edit mode type (default: "None")
176
- - `AutoNavigate`: boolean - Whether to auto-navigate on row click (default: true)
177
- - `AllowLoad`: boolean - Whether to allow loading data (default: true)
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
- - `rowClicked`: EventEmitter<GridRowClickedEvent> - Emitted when a row is clicked
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
- - `Refresh(params: RunQueryParams)`: Refreshes the grid data with the given query parameters
186
- - `RefreshFromSavedParams()`: Refreshes the grid data using the previously saved parameters
187
- - `doExcelExport()`: Exports the current grid data to Excel
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
- ## Query Parameters
200
-
201
- The component accepts a `RunQueryParams` object that specifies which query to run:
202
-
274
+ #### RunQueryParams (from @memberjunction/core)
203
275
  ```typescript
204
- const queryParams: RunQueryParams = {
205
- QueryID: 'MyQueryID', // ID of the query to run
206
- Parameters: [ // Optional query parameters
207
- { Name: 'Param1', Value: 'Value1' },
208
- { Name: 'Param2', Value: 42 }
209
- ],
210
- MaxRows: 1000 // Optional maximum rows to return
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
- ## Excel Export
288
+ ## Grid Configuration
215
289
 
216
- The component includes built-in Excel export functionality. Users can click the Excel export button in the grid toolbar to download the current data as an Excel file. The file will be named based on the QueryID (e.g., "MyQueryID_Query.xlsx").
290
+ The component uses Kendo UI Grid with the following configuration:
217
291
 
218
- ## Grid Features
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
- The grid component leverages Kendo UI Grid and includes the following features:
298
+ ## Excel Export
221
299
 
222
- - Virtual scrolling for performance with large datasets
223
- - Column resizing, reordering, and sorting
224
- - Row selection
225
- - Pagination with configurable page size
226
- - Loading indicator during data fetch
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 Kendo UI Grid component styles and includes basic CSS that can be overridden in your application.
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
- - `@memberjunction/core`: For metadata and query execution
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
- - `@progress/kendo-angular-grid`: For the grid component
239
- - `@progress/kendo-angular-excel-export`: For Excel export functionality
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.43.0",
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.43.0",
32
- "@memberjunction/global": "2.43.0",
33
- "@memberjunction/core": "2.43.0",
34
- "@memberjunction/ng-container-directives": "2.43.0",
35
- "@memberjunction/ng-compare-records": "2.43.0",
36
- "@memberjunction/ng-shared": "2.43.0",
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