@memberjunction/ng-base-forms 2.43.0 → 2.45.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 +285 -70
  2. package/package.json +10 -10
package/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # @memberjunction/ng-base-forms
2
2
 
3
- Base classes for creating entity forms in MemberJunction Angular applications, providing core functionality for form management, validation, and data handling.
3
+ Base classes and components for creating entity forms in MemberJunction Angular applications, providing core functionality for form management, validation, and data handling.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - Abstract base classes for forms, form sections, and record components
8
+ - Automatic field rendering components with type detection
8
9
  - Support for edit mode and validation
9
10
  - Transaction management for saving related records
10
11
  - Integration with MemberJunction metadata and entity framework
@@ -12,6 +13,8 @@ Base classes for creating entity forms in MemberJunction Angular applications, p
12
13
  - Permission checking and user authorization
13
14
  - Support for favorites and record dependencies
14
15
  - Form event handling and coordination
16
+ - Dynamic form section loading
17
+ - Linked record field components with search and dropdown capabilities
15
18
 
16
19
  ## Installation
17
20
 
@@ -19,13 +22,89 @@ Base classes for creating entity forms in MemberJunction Angular applications, p
19
22
  npm install @memberjunction/ng-base-forms
20
23
  ```
21
24
 
22
- ## Usage
25
+ ## Core Components
23
26
 
24
- This package provides several base classes that form the foundation for MemberJunction entity forms:
27
+ ### MJFormField
28
+
29
+ A powerful component that automatically generates UI for any field in a BaseEntity object:
30
+
31
+ ```typescript
32
+ import { Component } from '@angular/core';
33
+ import { BaseEntity } from '@memberjunction/core';
34
+
35
+ @Component({
36
+ template: `
37
+ <mj-form-field
38
+ [record]="myRecord"
39
+ [EditMode]="isEditing"
40
+ FieldName="FirstName"
41
+ Type="textbox"
42
+ [ShowLabel]="true"
43
+ (ValueChange)="onValueChange($event)"
44
+ ></mj-form-field>
45
+ `
46
+ })
47
+ export class MyComponent {
48
+ myRecord: BaseEntity;
49
+ isEditing: boolean = false;
50
+
51
+ onValueChange(newValue: any) {
52
+ console.log('Field value changed:', newValue);
53
+ }
54
+ }
55
+ ```
56
+
57
+ #### MJFormField Input Properties
58
+
59
+ - `record` (BaseEntity, required): The entity record containing the field
60
+ - `EditMode` (boolean): Whether the field is editable
61
+ - `FieldName` (string, required): Name of the field to render
62
+ - `Type` (string): Control type - 'textbox' | 'textarea' | 'numerictextbox' | 'datepicker' | 'checkbox' | 'dropdownlist' | 'combobox' | 'code'
63
+ - `LinkType` (string): For linked fields - 'Email' | 'URL' | 'Record' | 'None'
64
+ - `LinkComponentType` (string): For record links - 'Search' | 'Dropdown'
65
+ - `ShowLabel` (boolean): Whether to show the field label (default: true)
66
+ - `DisplayName` (string): Override the default display name
67
+ - `PossibleValues` (string[]): Custom values for dropdown/combobox fields
68
+
69
+ ### MJLinkField
70
+
71
+ Specialized component for fields that link to other entity records:
72
+
73
+ ```typescript
74
+ <mj-link-field
75
+ [record]="myRecord"
76
+ FieldName="CustomerID"
77
+ [RecordName]="customerName"
78
+ LinkComponentType="Search"
79
+ ></mj-link-field>
80
+ ```
81
+
82
+ #### MJLinkField Input Properties
83
+
84
+ - `record` (BaseEntity, required): The entity record
85
+ - `FieldName` (string, required): The foreign key field name
86
+ - `RecordName` (string): Pre-populate with the linked record's name
87
+ - `LinkComponentType` ('Search' | 'Dropdown'): UI type for selecting records
88
+
89
+ ### SectionLoaderComponent
90
+
91
+ Dynamically loads form sections registered with the MemberJunction class factory:
92
+
93
+ ```typescript
94
+ <mj-form-section
95
+ Entity="Customer"
96
+ Section="Details"
97
+ [record]="customerRecord"
98
+ [EditMode]="isEditing"
99
+ (LoadComplete)="onSectionLoaded()"
100
+ ></mj-form-section>
101
+ ```
102
+
103
+ ## Base Classes
25
104
 
26
105
  ### BaseRecordComponent
27
106
 
28
- The most basic component for working with entity records:
107
+ The foundational class for all components that work with entity records:
29
108
 
30
109
  ```typescript
31
110
  import { BaseRecordComponent } from '@memberjunction/ng-base-forms';
@@ -34,160 +113,296 @@ import { BaseRecordComponent } from '@memberjunction/ng-base-forms';
34
113
  // ...
35
114
  })
36
115
  export class YourComponent extends BaseRecordComponent {
37
- // Your record component implementation
116
+ // Inherited properties:
117
+ // - record: BaseEntity
118
+ // - EditMode: boolean
119
+ // - UserCanEdit: boolean
120
+ // - UserCanDelete: boolean
121
+ // - IsFavorite: boolean
38
122
  }
39
123
  ```
40
124
 
41
125
  ### BaseFormSectionComponent
42
126
 
43
- For creating form sections that can be used with entity forms:
127
+ For creating reusable form sections that can be dynamically loaded:
44
128
 
45
129
  ```typescript
46
130
  import { BaseFormSectionComponent } from '@memberjunction/ng-base-forms';
47
131
  import { RegisterClass } from '@memberjunction/global';
48
132
 
49
133
  @Component({
50
- // ...
134
+ template: `
135
+ <div class="form-section">
136
+ <!-- Your section UI here -->
137
+ </div>
138
+ `
51
139
  })
52
- @RegisterClass(BaseFormSectionComponent, 'YourEntity.SectionName')
53
- export class YourFormSectionComponent extends BaseFormSectionComponent {
54
- // Your form section implementation
140
+ @RegisterClass(BaseFormSectionComponent, 'Customer.Details')
141
+ export class CustomerDetailsSection extends BaseFormSectionComponent {
142
+ // Custom section logic
55
143
  }
56
144
  ```
57
145
 
58
146
  ### BaseFormComponent
59
147
 
60
- For creating complete entity forms:
148
+ For creating complete entity forms with full lifecycle management:
61
149
 
62
150
  ```typescript
63
151
  import { BaseFormComponent } from '@memberjunction/ng-base-forms';
64
152
  import { RegisterClass } from '@memberjunction/global';
65
153
 
66
154
  @Component({
67
- // ...
155
+ template: `
156
+ <form>
157
+ <mj-tab-strip>
158
+ <mj-tab title="Details">
159
+ <mj-form-section Entity="Customer" Section="Details"
160
+ [record]="record" [EditMode]="EditMode">
161
+ </mj-form-section>
162
+ </mj-tab>
163
+ </mj-tab-strip>
164
+ </form>
165
+ `
68
166
  })
69
- @RegisterClass(BaseFormComponent, 'YourEntity')
70
- export class YourFormComponent extends BaseFormComponent {
71
- // Your form implementation
167
+ @RegisterClass(BaseFormComponent, 'Customer')
168
+ export class CustomerFormComponent extends BaseFormComponent {
169
+ // Form-specific logic
72
170
  }
73
171
  ```
74
172
 
75
173
  ## Core Features
76
174
 
77
- ### Edit Mode
78
-
79
- Manage form edit states:
175
+ ### Edit Mode Management
80
176
 
81
177
  ```typescript
82
178
  // Start editing
83
179
  this.StartEditMode();
84
180
 
85
- // Save changes
86
- await this.SaveRecord(true); // true to stop edit mode after save
181
+ // Save changes (true = stop edit mode after save)
182
+ await this.SaveRecord(true);
87
183
 
88
- // Cancel editing
184
+ // Cancel editing and revert changes
89
185
  this.CancelEdit();
186
+
187
+ // Check if in edit mode
188
+ if (this.EditMode) {
189
+ // Show save/cancel buttons
190
+ }
90
191
  ```
91
192
 
92
193
  ### Validation
93
194
 
94
- Validate forms and handle validation errors:
95
-
96
195
  ```typescript
196
+ // Validate the entire form
97
197
  const validationResult = this.Validate();
98
198
  if (!validationResult.Success) {
99
- // Handle validation errors
100
- console.log(validationResult.Errors);
199
+ console.log('Validation errors:', validationResult.Errors);
101
200
  }
201
+
202
+ // Validate pending records
203
+ const pendingResults = this.ValidatePendingRecords();
102
204
  ```
103
205
 
104
206
  ### Permission Checking
105
207
 
106
- Check user permissions for operations:
107
-
108
208
  ```typescript
209
+ // Check user permissions
109
210
  if (this.UserCanEdit) {
110
- // Show edit controls
211
+ this.StartEditMode();
111
212
  }
112
213
 
113
214
  if (this.UserCanDelete) {
114
- // Show delete controls
215
+ // Show delete button
115
216
  }
116
- ```
117
217
 
118
- ### Related Records
218
+ // Check field-level permissions
219
+ const canEditField = this.UserCanEditField('FieldName');
220
+ ```
119
221
 
120
- Work with related entities:
222
+ ### Working with Related Records
121
223
 
122
224
  ```typescript
123
- // Get view parameters for a related entity
124
- const viewParams = this.BuildRelationshipViewParamsByEntityName('RelatedEntity');
225
+ // Get view parameters for related entity
226
+ const viewParams = this.BuildRelationshipViewParamsByEntityName('Orders');
125
227
 
126
- // Create new related records with pre-filled values
127
- const newValues = this.NewRecordValues('RelatedEntity');
128
- ```
228
+ // Create new related record with pre-filled values
229
+ const newOrderValues = this.NewRecordValues('Orders');
230
+ newOrderValues.CustomerID = this.record.ID;
129
231
 
130
- ### Tabbed Interface
232
+ // Access pending records for transaction
233
+ const pendingOrders = this.PendingRecords.filter(r => r.Entity === 'Orders');
234
+ ```
131
235
 
132
- Manage tabs in forms:
236
+ ### Tab Management
133
237
 
134
238
  ```typescript
135
- // Check if a tab is active
239
+ // Check active tab
136
240
  if (this.IsCurrentTab('details')) {
137
- // Perform tab-specific actions
241
+ // Load tab-specific data
138
242
  }
139
243
 
140
- // Respond to tab selection
244
+ // Handle tab selection
141
245
  public onTabSelect(e: TabEvent) {
142
- // Handle tab selection
246
+ this.LoadTabData(e.title);
247
+ }
248
+
249
+ // Tab configuration
250
+ tabs = [
251
+ { title: 'Details', selected: true },
252
+ { title: 'Orders', selected: false },
253
+ { title: 'History', selected: false }
254
+ ];
255
+ ```
256
+
257
+ ### Favorites Management
258
+
259
+ ```typescript
260
+ // Check if record is favorited
261
+ if (this.IsFavorite) {
262
+ // Show filled star icon
263
+ }
264
+
265
+ // Toggle favorite status
266
+ if (this.IsFavorite) {
267
+ await this.RemoveFavorite();
268
+ } else {
269
+ await this.MakeFavorite();
143
270
  }
144
271
  ```
145
272
 
146
- ## Advanced Features
273
+ ### Record Dependencies
147
274
 
148
- ### Pending Records
275
+ ```typescript
276
+ // Check for dependencies before delete
277
+ const dependencies = await this.GetRecordDependencies();
278
+ if (dependencies.length > 0) {
279
+ // Show warning about dependent records
280
+ console.log(`Cannot delete: ${dependencies.length} dependent records found`);
281
+ }
282
+ ```
283
+
284
+ ## Advanced Usage
149
285
 
150
- Manage related records in a transaction:
286
+ ### Custom Field Rendering
287
+
288
+ Override default field rendering by creating custom components:
151
289
 
152
290
  ```typescript
153
- // Access pending records
154
- const pendingRecords = this.PendingRecords;
291
+ @Component({
292
+ selector: 'custom-field',
293
+ template: `
294
+ <div class="custom-field">
295
+ <label>{{ field.DisplayName }}</label>
296
+ <custom-control [value]="value" (change)="onChange($event)">
297
+ </custom-control>
298
+ </div>
299
+ `
300
+ })
301
+ export class CustomFieldComponent {
302
+ @Input() field: EntityFieldInfo;
303
+ @Input() value: any;
304
+ @Output() valueChange = new EventEmitter<any>();
305
+ }
306
+ ```
307
+
308
+ ### Dynamic Form Section Registration
309
+
310
+ Register form sections to be dynamically loaded:
311
+
312
+ ```typescript
313
+ // In your module or component
314
+ import { RegisterClass } from '@memberjunction/global';
315
+
316
+ @RegisterClass(BaseFormSectionComponent, 'Product.Inventory')
317
+ export class ProductInventorySection extends BaseFormSectionComponent {
318
+ // Section implementation
319
+ }
155
320
 
156
- // Process records before save
157
- this.PopulatePendingRecords();
321
+ // Usage in template
322
+ <mj-form-section Entity="Product" Section="Inventory"
323
+ [record]="productRecord" [EditMode]="EditMode">
324
+ </mj-form-section>
325
+ ```
326
+
327
+ ### Transaction Management
328
+
329
+ Handle multiple related records in a single transaction:
330
+
331
+ ```typescript
332
+ // Add records to pending transaction
333
+ this.AddPendingRecord(newOrderRecord, 'Orders');
334
+ this.AddPendingRecord(newOrderItemRecord, 'Order Items');
158
335
 
159
336
  // Validate all pending records
160
337
  const validationResults = this.ValidatePendingRecords();
338
+ if (validationResults.every(r => r.Success)) {
339
+ // Save all records in transaction
340
+ await this.SaveRecord(true);
341
+ }
161
342
  ```
162
343
 
163
- ### Favorites
344
+ ## Module Configuration
164
345
 
165
- Manage record favorites:
346
+ The BaseFormsModule includes all necessary imports:
166
347
 
167
348
  ```typescript
168
- // Check if record is a favorite
169
- if (this.IsFavorite) {
170
- // Show "Remove from favorites" option
171
- }
349
+ import { BaseFormsModule } from '@memberjunction/ng-base-forms';
172
350
 
173
- // Add/remove from favorites
174
- await this.MakeFavorite();
175
- await this.RemoveFavorite();
351
+ @NgModule({
352
+ imports: [
353
+ BaseFormsModule,
354
+ // Other imports...
355
+ ]
356
+ })
357
+ export class YourModule { }
176
358
  ```
177
359
 
178
- ### Record Dependencies
360
+ ## Dependencies
179
361
 
180
- View record dependencies:
362
+ - **Angular Core**: v18.0.2+
363
+ - **@memberjunction/core**: Core MJ functionality
364
+ - **@memberjunction/global**: Global utilities and class factory
365
+ - **@memberjunction/ng-shared**: Shared Angular services
366
+ - **@memberjunction/ng-tabstrip**: Tab management
367
+ - **@memberjunction/ng-link-directives**: Link handling
368
+ - **@memberjunction/ng-container-directives**: Container utilities
369
+ - **@memberjunction/ng-record-changes**: Change tracking
370
+ - **@memberjunction/ng-code-editor**: Code editing support
371
+ - **@progress/kendo-angular-\***: UI components
372
+ - **ngx-markdown**: Markdown rendering
373
+ - **rxjs**: Reactive programming
181
374
 
182
- ```typescript
183
- // Show dependencies
184
- const dependencies = await this.GetRecordDependencies();
375
+ ## Integration with MemberJunction
376
+
377
+ This package is designed to work seamlessly with the MemberJunction ecosystem:
378
+
379
+ - **Entity Metadata**: Automatically reads field definitions, relationships, and permissions
380
+ - **Class Factory**: Uses MJ's class factory for dynamic component loading
381
+ - **Validation**: Integrates with entity-level validation rules
382
+ - **Permissions**: Respects entity and field-level permissions
383
+ - **Transactions**: Supports MJ's transaction management for related records
384
+
385
+ ## Best Practices
386
+
387
+ 1. **Always use the class factory** for registering custom form components
388
+ 2. **Leverage MJFormField** for automatic field rendering when possible
389
+ 3. **Handle validation** at both field and form levels
390
+ 4. **Check permissions** before allowing user actions
391
+ 5. **Use transactions** when saving multiple related records
392
+ 6. **Implement proper error handling** for save operations
393
+ 7. **Follow Angular lifecycle** hooks for initialization and cleanup
394
+
395
+ ## Building
396
+
397
+ This package uses Angular CLI for building:
398
+
399
+ ```bash
400
+ # Build the package
401
+ npm run build
402
+
403
+ # The built package will be in the dist/ directory
185
404
  ```
186
405
 
187
- ## Integration
406
+ ## License
188
407
 
189
- This package integrates with other MemberJunction components:
190
- - Uses `@memberjunction/ng-base-types` for event handling
191
- - Uses `@memberjunction/ng-shared` for shared services
192
- - Uses `@memberjunction/ng-tabstrip` for tab management
193
- - Works with `@memberjunction/core` entities and metadata
408
+ ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-base-forms",
3
- "version": "2.43.0",
3
+ "version": "2.45.0",
4
4
  "description": "MemberJunction: Angular Base Form Components",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -25,15 +25,15 @@
25
25
  "@angular/router": "18.0.2"
26
26
  },
27
27
  "dependencies": {
28
- "@memberjunction/global": "2.43.0",
29
- "@memberjunction/core": "2.43.0",
30
- "@memberjunction/ng-code-editor": "2.43.0",
31
- "@memberjunction/ng-shared": "2.43.0",
32
- "@memberjunction/ng-tabstrip": "2.43.0",
33
- "@memberjunction/ng-link-directives": "2.43.0",
34
- "@memberjunction/ng-container-directives": "2.43.0",
35
- "@memberjunction/ng-record-changes": "2.43.0",
36
- "@memberjunction/ng-base-types": "2.43.0",
28
+ "@memberjunction/global": "2.45.0",
29
+ "@memberjunction/core": "2.45.0",
30
+ "@memberjunction/ng-code-editor": "2.45.0",
31
+ "@memberjunction/ng-shared": "2.45.0",
32
+ "@memberjunction/ng-tabstrip": "2.45.0",
33
+ "@memberjunction/ng-link-directives": "2.45.0",
34
+ "@memberjunction/ng-container-directives": "2.45.0",
35
+ "@memberjunction/ng-record-changes": "2.45.0",
36
+ "@memberjunction/ng-base-types": "2.45.0",
37
37
  "@progress/kendo-angular-buttons": "16.2.0",
38
38
  "@progress/kendo-angular-dropdowns": "16.2.0",
39
39
  "@progress/kendo-angular-inputs": "16.2.0",