@memberjunction/ng-record-selector 2.42.1 → 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 +181 -54
  2. package/package.json +6 -6
package/README.md CHANGED
@@ -1,17 +1,22 @@
1
- # Record Selector Component
1
+ # @memberjunction/ng-record-selector
2
2
 
3
- An Angular component for selecting records from a list of available items in MemberJunction applications. This package provides both a standalone selection component and a dialog wrapper component for easy integration.
3
+ An Angular component library for selecting records from dual lists in MemberJunction applications. This package provides both a standalone selection component and a dialog wrapper component for easy integration.
4
+
5
+ ## Overview
6
+
7
+ The `@memberjunction/ng-record-selector` package provides Angular components that allow users to select and deselect items from a possible set using a dual listbox interface. It's designed to work seamlessly with MemberJunction's BaseEntity objects and provides a clean, intuitive UI for managing selections.
4
8
 
5
9
  ## Features
6
10
 
7
- - **Dual Listbox Interface**: Easy selection between available and selected items
8
- - **Drag and Drop**: Intuitive item movement between lists
9
- - **Double-Click Support**: Quickly move items by double-clicking
10
- - **Icon Support**: Display icons alongside item text
11
- - **Configurable Toolbar**: Customize available toolbar actions
12
- - **Dialog Integration**: Optional dialog wrapper for modal usage
13
- - **Entity Integration**: Works with MemberJunction BaseEntity objects
14
- - **Memory Management**: Maintains selection state within dialog sessions
11
+ - **Dual Listbox Interface**: Side-by-side lists for available and selected items
12
+ - **Drag and Drop**: Intuitive item movement between lists using Kendo UI's drag and drop functionality
13
+ - **Double-Click Support**: Quickly move items between lists by double-clicking
14
+ - **Icon Support**: Display icons alongside item text using CSS classes from entity fields
15
+ - **Configurable Toolbar**: Customize available toolbar actions (move up/down, transfer items, transfer all)
16
+ - **Dialog Integration**: Optional dialog wrapper for modal usage with OK/Cancel functionality
17
+ - **Entity Integration**: Works natively with MemberJunction BaseEntity objects
18
+ - **State Management**: Dialog component maintains selection state and can revert changes on cancel
19
+ - **Responsive Design**: Uses MemberJunction's container directives for proper layout
15
20
 
16
21
  ## Installation
17
22
 
@@ -19,6 +24,8 @@ An Angular component for selecting records from a list of available items in Mem
19
24
  npm install @memberjunction/ng-record-selector
20
25
  ```
21
26
 
27
+ Note: This package has peer dependencies on Angular 18.0.2 and Kendo UI Angular components. Ensure these are installed in your project.
28
+
22
29
  ## Usage
23
30
 
24
31
  ### Import the Module
@@ -42,8 +49,8 @@ export class YourModule { }
42
49
  <!-- Standalone selector component -->
43
50
  <mj-record-selector
44
51
  [EntityName]="'Users'"
45
- [DisplayField]="'UserName'"
46
- [DisplayIconField]="'UserIcon'"
52
+ [DisplayField]="'Name'"
53
+ [DisplayIconField]="'IconCSSClass'"
47
54
  [AvailableRecords]="allUsers"
48
55
  [SelectedRecords]="selectedUsers"
49
56
  [UnselectedRecords]="unselectedUsers"
@@ -52,6 +59,8 @@ export class YourModule { }
52
59
  </mj-record-selector>
53
60
  ```
54
61
 
62
+ **Note**: The component accesses entity field values directly using bracket notation (e.g., `dataItem[DisplayField]`), so ensure your DisplayField and DisplayIconField names match the actual property names in your BaseEntity objects.
63
+
55
64
  ### Dialog Component Usage
56
65
 
57
66
  ```html
@@ -63,7 +72,8 @@ export class YourModule { }
63
72
  <mj-record-selector-dialog
64
73
  *ngIf="showSelectorDialog"
65
74
  [EntityName]="'Users'"
66
- [DisplayField]="'UserName'"
75
+ [DisplayField]="'Name'"
76
+ [DisplayIconField]="'IconCSSClass'"
67
77
  [AvailableRecords]="allUsers"
68
78
  [SelectedRecords]="selectedUsers"
69
79
  [UnselectedRecords]="unselectedUsers"
@@ -80,6 +90,7 @@ export class YourModule { }
80
90
  ```typescript
81
91
  import { Component, OnInit } from '@angular/core';
82
92
  import { BaseEntity, Metadata, RunView } from '@memberjunction/core';
93
+ import { UserEntity } from '@memberjunction/core-entities';
83
94
  import { ListBoxToolbarConfig } from '@progress/kendo-angular-listbox';
84
95
 
85
96
  @Component({
@@ -92,7 +103,7 @@ import { ListBoxToolbarConfig } from '@progress/kendo-angular-listbox';
92
103
  <h4>Selected Users ({{ selectedUsers.length }}):</h4>
93
104
  <ul>
94
105
  <li *ngFor="let user of selectedUsers">
95
- {{ user.Get('UserName') }} - {{ user.Get('Email') }}
106
+ {{ user.Name }} - {{ user.Email }}
96
107
  </li>
97
108
  </ul>
98
109
  <button kendoButton (click)="saveUserAssignments()">Save Assignments</button>
@@ -101,8 +112,8 @@ import { ListBoxToolbarConfig } from '@progress/kendo-angular-listbox';
101
112
  <mj-record-selector-dialog
102
113
  *ngIf="selectorDialogVisible"
103
114
  [EntityName]="'Users'"
104
- [DisplayField]="'UserName'"
105
- [DisplayIconField]="'UserIcon'"
115
+ [DisplayField]="'Name'"
116
+ [DisplayIconField]="'IconCSSClass'"
106
117
  [AvailableRecords]="allUsers"
107
118
  [SelectedRecords]="selectedUsers"
108
119
  [UnselectedRecords]="unselectedUsers"
@@ -116,9 +127,9 @@ import { ListBoxToolbarConfig } from '@progress/kendo-angular-listbox';
116
127
  `
117
128
  })
118
129
  export class UserRoleAssignmentComponent implements OnInit {
119
- allUsers: BaseEntity[] = [];
120
- selectedUsers: BaseEntity[] = [];
121
- unselectedUsers: BaseEntity[] = [];
130
+ allUsers: UserEntity[] = [];
131
+ selectedUsers: UserEntity[] = [];
132
+ unselectedUsers: UserEntity[] = [];
122
133
  selectorDialogVisible = false;
123
134
 
124
135
  toolbarSettings: ListBoxToolbarConfig = {
@@ -133,9 +144,9 @@ export class UserRoleAssignmentComponent implements OnInit {
133
144
  }
134
145
 
135
146
  async loadUsers() {
136
- // Load all users
147
+ // Load all users using MemberJunction's recommended pattern
137
148
  const rv = new RunView();
138
- const result = await rv.RunView({
149
+ const result = await rv.RunView<UserEntity>({
139
150
  EntityName: 'Users',
140
151
  ResultType: 'entity_object'
141
152
  });
@@ -159,14 +170,19 @@ export class UserRoleAssignmentComponent implements OnInit {
159
170
 
160
171
  if (confirmed) {
161
172
  console.log('User selection confirmed:', this.selectedUsers);
173
+ // The selectedUsers array has been updated by the dialog component
162
174
  } else {
163
175
  console.log('User selection cancelled');
176
+ // The dialog component has already reverted any changes
164
177
  }
165
178
  }
166
179
 
167
- saveUserAssignments() {
168
- // Logic to save user role assignments
169
- console.log('Saving role assignments for users:', this.selectedUsers);
180
+ async saveUserAssignments() {
181
+ // Example: Save user role assignments
182
+ for (const user of this.selectedUsers) {
183
+ // Create role assignment records or update user roles
184
+ console.log(`Assigning role to user: ${user.Name} (${user.ID})`);
185
+ }
170
186
  }
171
187
  }
172
188
  ```
@@ -175,39 +191,72 @@ export class UserRoleAssignmentComponent implements OnInit {
175
191
 
176
192
  ### RecordSelectorComponent
177
193
 
178
- Standalone component for selecting records.
194
+ The base component that provides the dual listbox functionality for selecting records.
195
+
196
+ **Selector**: `mj-record-selector`
179
197
 
180
198
  #### Inputs
181
199
 
182
- - `EntityName`: string - The name of the entity to show records for
183
- - `DisplayField`: string - The field name to display in the list items
184
- - `DisplayIconField`: string - The field name containing CSS class for icons (optional)
185
- - `AvailableRecords`: BaseEntity[] - List of all available records
186
- - `SelectedRecords`: BaseEntity[] - List of selected records
187
- - `UnselectedRecords`: BaseEntity[] - List of unselected records
188
- - `ToolbarSettings`: ListBoxToolbarConfig - Configuration for the listbox toolbar
200
+ | Input | Type | Default | Description |
201
+ |-------|------|---------|-------------|
202
+ | `EntityName` | `string` | `''` | The name of the entity to show records for |
203
+ | `DisplayField` | `string` | `''` | The field name to display in the list items |
204
+ | `DisplayIconField` | `string` | `''` | The field name containing CSS class for icons (optional) |
205
+ | `AvailableRecords` | `BaseEntity[]` | `[]` | List of all available records |
206
+ | `SelectedRecords` | `BaseEntity[]` | `[]` | List of currently selected records |
207
+ | `UnselectedRecords` | `BaseEntity[]` | `[]` | List of currently unselected records |
208
+ | `ToolbarSettings` | `ListBoxToolbarConfig` | See below | Configuration for the listbox toolbar |
209
+
210
+ Default toolbar settings:
211
+ ```typescript
212
+ {
213
+ position: "right",
214
+ tools: ["moveUp", "transferFrom", "transferAllFrom", "transferAllTo", "transferTo", "moveDown"]
215
+ }
216
+ ```
189
217
 
190
218
  #### Outputs
191
219
 
192
- - `RecordSelected`: EventEmitter<BaseEntity[]> - Emitted when records are selected
193
- - `RecordUnselected`: EventEmitter<BaseEntity[]> - Emitted when records are unselected
220
+ | Output | Type | Description |
221
+ |--------|------|-------------|
222
+ | `RecordSelected` | `EventEmitter<BaseEntity[]>` | Emitted when records are moved to the selected list |
223
+ | `RecordUnselected` | `EventEmitter<BaseEntity[]>` | Emitted when records are moved to the unselected list |
224
+
225
+ #### Methods
226
+
227
+ The component handles double-click events internally to move items between lists. No public methods are exposed.
194
228
 
195
229
  ### RecordSelectorDialogComponent
196
230
 
197
- Dialog wrapper for the RecordSelectorComponent.
231
+ A dialog wrapper that contains the RecordSelectorComponent with OK/Cancel functionality.
232
+
233
+ **Selector**: `mj-record-selector-dialog`
198
234
 
199
235
  #### Inputs
200
236
 
201
- - All inputs from RecordSelectorComponent, plus:
202
- - `DialogTitle`: string - Title of the dialog (default: 'Select Records')
203
- - `DialogWidth`: string - Width of the dialog (default: '700px')
204
- - `DialogHeight`: string - Height of the dialog (default: '450px')
205
- - `DialogVisible`: boolean - Controls the visibility of the dialog
237
+ Inherits all inputs from `RecordSelectorComponent`, plus:
238
+
239
+ | Input | Type | Default | Description |
240
+ |-------|------|---------|-------------|
241
+ | `DialogTitle` | `string` | `'Select Records'` | Title displayed in the dialog header |
242
+ | `DialogWidth` | `string` | `'700px'` | Width of the dialog |
243
+ | `DialogHeight` | `string` | `'450px'` | Height of the dialog |
244
+ | `DialogVisible` | `boolean` | `false` | Controls the visibility of the dialog |
206
245
 
207
246
  #### Outputs
208
247
 
209
- - All outputs from RecordSelectorComponent, plus:
210
- - `DialogClosed`: EventEmitter<boolean> - Emitted when the dialog is closed (true if confirmed, false if canceled)
248
+ Inherits all outputs from `RecordSelectorComponent`, plus:
249
+
250
+ | Output | Type | Description |
251
+ |--------|------|-------------|
252
+ | `DialogClosed` | `EventEmitter<boolean>` | Emitted when the dialog is closed. `true` if OK was clicked, `false` if Cancel was clicked or dialog was closed by other means |
253
+
254
+ #### Behavior
255
+
256
+ - When the dialog is opened, it saves the initial state of selected/unselected records
257
+ - Clicking OK commits the changes and closes the dialog
258
+ - Clicking Cancel or closing the dialog by other means reverts all changes to the initial state
259
+ - The component maintains references to the same arrays passed in as inputs, modifying them in place
211
260
 
212
261
  ## Toolbar Configuration
213
262
 
@@ -229,22 +278,100 @@ const toolbarSettings: ListBoxToolbarConfig = {
229
278
 
230
279
  ## Selection Behavior
231
280
 
232
- The component uses Kendo UI ListBox components with the following behavior:
281
+ The component uses Kendo UI ListBox components with the following interaction patterns:
233
282
 
234
- 1. Items can be moved between lists using the toolbar buttons
235
- 2. Items can be dragged and dropped between lists
236
- 3. Double-clicking an item moves it to the other list
237
- 4. When used in a dialog, changes are only committed when the OK button is clicked; Cancel reverts to the previous state
283
+ 1. **Toolbar Actions**: Use the toolbar buttons to move items between lists
284
+ 2. **Drag and Drop**: Items can be dragged from one list to another
285
+ 3. **Double-Click**: Double-clicking an item instantly moves it to the opposite list
286
+ 4. **Multi-Select**: Hold Ctrl/Cmd to select multiple items, or Shift to select a range
287
+ 5. **Dialog State Management**: When using the dialog wrapper:
288
+ - Changes are held in memory until confirmed
289
+ - OK button commits all changes
290
+ - Cancel button reverts to the initial state
238
291
 
239
292
  ## Styling
240
293
 
241
- The component uses Kendo UI ListBox component styles and includes basic CSS that can be overridden in your application.
294
+ The component uses Kendo UI ListBox styles with additional custom styling:
295
+
296
+ - `.list-box`: Applied to each listbox container
297
+ - `.item-icon`: Applied to icon spans when DisplayIconField is used
298
+
299
+ You can override these styles in your application's CSS:
300
+
301
+ ```css
302
+ /* Example: Custom styling for the record selector */
303
+ mj-record-selector .list-box {
304
+ min-height: 300px;
305
+ }
306
+
307
+ mj-record-selector .item-icon {
308
+ margin-right: 8px;
309
+ color: #666;
310
+ }
311
+ ```
242
312
 
243
313
  ## Dependencies
244
314
 
245
- - `@memberjunction/core`: For metadata and entity types
246
- - `@memberjunction/core-entities`: For entity types
247
- - `@memberjunction/global`: For global utilities
248
- - `@progress/kendo-angular-listbox`: For the list box component
249
- - `@progress/kendo-angular-buttons`: For UI buttons
250
- - `@progress/kendo-angular-dialog`: For dialog wrapper
315
+ ### Runtime Dependencies
316
+ - `@memberjunction/core`: ^2.43.0 - Core MemberJunction functionality
317
+ - `@memberjunction/core-entities`: ^2.43.0 - Entity type definitions
318
+ - `@memberjunction/global`: ^2.43.0 - Global utilities and types
319
+ - `@memberjunction/ng-container-directives`: ^2.43.0 - Layout directives
320
+ - `@memberjunction/ng-shared`: ^2.43.0 - Shared Angular utilities
321
+
322
+ ### Peer Dependencies
323
+ - `@angular/common`: 18.0.2
324
+ - `@angular/core`: 18.0.2
325
+ - `@angular/forms`: 18.0.2
326
+ - `@angular/router`: 18.0.2
327
+ - `@progress/kendo-angular-buttons`: 16.2.0
328
+ - `@progress/kendo-angular-dialog`: 16.2.0
329
+ - `@progress/kendo-angular-listbox`: 16.2.0
330
+
331
+ ## Integration with Other MemberJunction Packages
332
+
333
+ This package integrates seamlessly with other MemberJunction components:
334
+
335
+ - **Entity Framework**: Works with any BaseEntity subclass from `@memberjunction/core`
336
+ - **Metadata System**: Compatible with entities loaded through the MJ metadata system
337
+ - **Container Directives**: Uses `mjFillContainer` directive for proper layout integration
338
+ - **RunView**: Designed to work with records loaded via RunView queries
339
+
340
+ ## Common Use Cases
341
+
342
+ 1. **User Role Assignment**: Select users to assign to specific roles
343
+ 2. **Permission Management**: Choose permissions to grant to users or roles
344
+ 3. **Category Assignment**: Assign items to multiple categories
345
+ 4. **Team Membership**: Manage team member selections
346
+ 5. **Feature Selection**: Enable/disable features for specific tenants
347
+
348
+ ## Best Practices
349
+
350
+ 1. **Data Loading**: Always use the MemberJunction RunView pattern with `ResultType: 'entity_object'` for optimal performance
351
+ 2. **Memory Management**: The dialog component maintains state internally, so you don't need to manage temporary arrays
352
+ 3. **Field Names**: Ensure DisplayField matches actual property names in your entities (not the Get() method parameters)
353
+ 4. **Icon Fields**: If using DisplayIconField, ensure the field contains valid CSS class names (e.g., 'fa-user', 'fas fa-star')
354
+ 5. **Array References**: The component modifies the input arrays in place, so use the same array references throughout your component's lifecycle
355
+
356
+ ## Troubleshooting
357
+
358
+ ### Records not displaying
359
+ - Verify that DisplayField matches an actual property name in your BaseEntity objects
360
+ - Check that AvailableRecords is populated with valid BaseEntity instances
361
+ - Ensure SelectedRecords and UnselectedRecords are subsets of AvailableRecords
362
+
363
+ ### Icons not showing
364
+ - Confirm DisplayIconField contains valid CSS class names
365
+ - Ensure required icon fonts (Font Awesome, etc.) are loaded in your application
366
+
367
+ ### Dialog state issues
368
+ - Make sure DialogVisible is properly bound and updated
369
+ - Handle the DialogClosed event to update your component's state
370
+
371
+ ## Version History
372
+
373
+ See [CHANGELOG.md](./CHANGELOG.md) for detailed version history.
374
+
375
+ ## License
376
+
377
+ ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-record-selector",
3
- "version": "2.42.1",
3
+ "version": "2.44.0",
4
4
  "description": "MemberJunction: Angular Components to allow a user to select/deselect items from a possible set",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -28,11 +28,11 @@
28
28
  "@progress/kendo-angular-listbox": "16.2.0"
29
29
  },
30
30
  "dependencies": {
31
- "@memberjunction/core-entities": "2.42.1",
32
- "@memberjunction/global": "2.42.1",
33
- "@memberjunction/core": "2.42.1",
34
- "@memberjunction/ng-container-directives": "2.42.1",
35
- "@memberjunction/ng-shared": "2.42.1",
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-shared": "2.44.0",
36
36
  "tslib": "^2.3.0"
37
37
  },
38
38
  "sideEffects": false