@memberjunction/ng-base-forms 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.
- package/dist/lib/base-form-component.d.ts +103 -215
- package/dist/lib/base-form-component.d.ts.map +1 -1
- package/dist/lib/base-form-component.js +384 -541
- package/dist/lib/base-form-component.js.map +1 -1
- package/dist/lib/container/record-form-container.component.d.ts +165 -0
- package/dist/lib/container/record-form-container.component.d.ts.map +1 -0
- package/dist/lib/container/record-form-container.component.js +534 -0
- package/dist/lib/container/record-form-container.component.js.map +1 -0
- package/dist/lib/explorer-entity-data-grid.component.d.ts +7 -5
- package/dist/lib/explorer-entity-data-grid.component.d.ts.map +1 -1
- package/dist/lib/explorer-entity-data-grid.component.js +15 -9
- package/dist/lib/explorer-entity-data-grid.component.js.map +1 -1
- package/dist/lib/field/form-field.component.d.ts +268 -0
- package/dist/lib/field/form-field.component.d.ts.map +1 -0
- package/dist/lib/field/form-field.component.js +1194 -0
- package/dist/lib/field/form-field.component.js.map +1 -0
- package/dist/lib/form-state.interface.d.ts +2 -0
- package/dist/lib/form-state.interface.d.ts.map +1 -1
- package/dist/lib/form-state.interface.js.map +1 -1
- package/dist/lib/form-state.service.d.ts +14 -0
- package/dist/lib/form-state.service.d.ts.map +1 -1
- package/dist/lib/form-state.service.js +19 -0
- package/dist/lib/form-state.service.js.map +1 -1
- package/dist/lib/panel/collapsible-panel.component.d.ts +139 -0
- package/dist/lib/panel/collapsible-panel.component.d.ts.map +1 -0
- package/dist/lib/panel/collapsible-panel.component.js +468 -0
- package/dist/lib/panel/collapsible-panel.component.js.map +1 -0
- package/dist/lib/toolbar/form-toolbar.component.d.ts +170 -0
- package/dist/lib/toolbar/form-toolbar.component.d.ts.map +1 -0
- package/dist/lib/toolbar/form-toolbar.component.js +830 -0
- package/dist/lib/toolbar/form-toolbar.component.js.map +1 -0
- package/dist/lib/types/form-events.d.ts +90 -0
- package/dist/lib/types/form-events.d.ts.map +1 -0
- package/dist/lib/types/form-events.js +45 -0
- package/dist/lib/types/form-events.js.map +1 -0
- package/dist/lib/types/form-types.d.ts +150 -0
- package/dist/lib/types/form-types.d.ts.map +1 -0
- package/dist/lib/types/form-types.js +12 -0
- package/dist/lib/types/form-types.js.map +1 -0
- package/dist/lib/types/navigation-events.d.ts +88 -0
- package/dist/lib/types/navigation-events.d.ts.map +1 -0
- package/dist/lib/types/navigation-events.js +2 -0
- package/dist/lib/types/navigation-events.js.map +1 -0
- package/dist/lib/types/toolbar-config.d.ts +66 -0
- package/dist/lib/types/toolbar-config.d.ts.map +1 -0
- package/dist/lib/types/toolbar-config.js +38 -0
- package/dist/lib/types/toolbar-config.js.map +1 -0
- package/dist/module.d.ts +28 -20
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +47 -74
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +20 -8
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +24 -9
- package/dist/public-api.js.map +1 -1
- package/package.json +20 -23
- package/README.md +0 -449
- package/dist/lib/base-field-component.d.ts +0 -152
- package/dist/lib/base-field-component.d.ts.map +0 -1
- package/dist/lib/base-field-component.js +0 -669
- package/dist/lib/base-field-component.js.map +0 -1
- package/dist/lib/base-form-context.d.ts +0 -23
- package/dist/lib/base-form-context.d.ts.map +0 -1
- package/dist/lib/base-form-context.js +0 -10
- package/dist/lib/base-form-context.js.map +0 -1
- package/dist/lib/collapsible-panel.component.d.ts +0 -68
- package/dist/lib/collapsible-panel.component.d.ts.map +0 -1
- package/dist/lib/collapsible-panel.component.js +0 -330
- package/dist/lib/collapsible-panel.component.js.map +0 -1
- package/dist/lib/form-section-controls.component.d.ts +0 -35
- package/dist/lib/form-section-controls.component.d.ts.map +0 -1
- package/dist/lib/form-section-controls.component.js +0 -273
- package/dist/lib/form-section-controls.component.js.map +0 -1
- package/dist/lib/link-field.component.d.ts +0 -62
- package/dist/lib/link-field.component.d.ts.map +0 -1
- package/dist/lib/link-field.component.js +0 -392
- package/dist/lib/link-field.component.js.map +0 -1
package/README.md
DELETED
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
# @memberjunction/ng-base-forms
|
|
2
|
-
|
|
3
|
-
Base classes and components for creating entity forms in MemberJunction Angular applications, providing core functionality for form management, validation, and data handling.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- Abstract base classes for forms, form sections, and record components
|
|
8
|
-
- Automatic field rendering components with type detection
|
|
9
|
-
- **Encrypted field support** with configurable visibility and blind edit modes
|
|
10
|
-
- Support for edit mode and validation
|
|
11
|
-
- Transaction management for saving related records
|
|
12
|
-
- Integration with MemberJunction metadata and entity framework
|
|
13
|
-
- Tab management and responsive design
|
|
14
|
-
- Permission checking and user authorization
|
|
15
|
-
- Support for favorites and record dependencies
|
|
16
|
-
- Form event handling and coordination
|
|
17
|
-
- Dynamic form section loading
|
|
18
|
-
- Linked record field components with search and dropdown capabilities
|
|
19
|
-
|
|
20
|
-
## Installation
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm install @memberjunction/ng-base-forms
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Core Components
|
|
27
|
-
|
|
28
|
-
### MJFormField
|
|
29
|
-
|
|
30
|
-
A powerful component that automatically generates UI for any field in a BaseEntity object:
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
import { Component } from '@angular/core';
|
|
34
|
-
import { BaseEntity } from '@memberjunction/core';
|
|
35
|
-
|
|
36
|
-
@Component({
|
|
37
|
-
template: `
|
|
38
|
-
<mj-form-field
|
|
39
|
-
[record]="myRecord"
|
|
40
|
-
[EditMode]="isEditing"
|
|
41
|
-
FieldName="FirstName"
|
|
42
|
-
Type="textbox"
|
|
43
|
-
[ShowLabel]="true"
|
|
44
|
-
(ValueChange)="onValueChange($event)"
|
|
45
|
-
></mj-form-field>
|
|
46
|
-
`
|
|
47
|
-
})
|
|
48
|
-
export class MyComponent {
|
|
49
|
-
myRecord: BaseEntity;
|
|
50
|
-
isEditing: boolean = false;
|
|
51
|
-
|
|
52
|
-
onValueChange(newValue: any) {
|
|
53
|
-
console.log('Field value changed:', newValue);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
#### MJFormField Input Properties
|
|
59
|
-
|
|
60
|
-
- `record` (BaseEntity, required): The entity record containing the field
|
|
61
|
-
- `EditMode` (boolean): Whether the field is editable
|
|
62
|
-
- `FieldName` (string, required): Name of the field to render
|
|
63
|
-
- `Type` (string): Control type - 'textbox' | 'textarea' | 'numerictextbox' | 'datepicker' | 'checkbox' | 'dropdownlist' | 'combobox' | 'code'
|
|
64
|
-
- `LinkType` (string): For linked fields - 'Email' | 'URL' | 'Record' | 'None'
|
|
65
|
-
- `LinkComponentType` (string): For record links - 'Search' | 'Dropdown'
|
|
66
|
-
- `ShowLabel` (boolean): Whether to show the field label (default: true)
|
|
67
|
-
- `DisplayName` (string): Override the default display name
|
|
68
|
-
- `PossibleValues` (string[]): Custom values for dropdown/combobox fields
|
|
69
|
-
- `formContext` (BaseFormContext): Form context for field filtering and state
|
|
70
|
-
- `hideWhenEmptyInReadOnlyMode` (boolean): Hide field when empty in read-only mode (default: true)
|
|
71
|
-
|
|
72
|
-
#### Encrypted Field Support
|
|
73
|
-
|
|
74
|
-
MJFormField automatically handles fields configured for encryption in the entity metadata. The component provides appropriate UI based on the field's encryption settings:
|
|
75
|
-
|
|
76
|
-
**Read-Only Mode:**
|
|
77
|
-
- **AllowDecryptInAPI=true**: Displays a masked value (••••••••) with a lock icon by default. Users can click the eye toggle button to reveal the actual decrypted value.
|
|
78
|
-
- **AllowDecryptInAPI=false**: Displays only the masked value with a lock icon. The value cannot be revealed as it's protected.
|
|
79
|
-
- **Empty value**: Displays nothing (no mask or icon).
|
|
80
|
-
|
|
81
|
-
**Edit Mode:**
|
|
82
|
-
- **AllowDecryptInAPI=true**: Shows a password-style text input with an eye toggle to show/hide the value being edited.
|
|
83
|
-
- **AllowDecryptInAPI=false ("Blind Edit")**: Shows the current value as locked/masked (cannot be viewed), with a separate empty text input for entering a new value. Users can use the eye toggle to verify what they're typing before submitting.
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
// Entity field metadata configuration for encryption
|
|
87
|
-
// (Set via database or entity metadata, not in Angular component)
|
|
88
|
-
// - Encrypt: true // Field value is encrypted at rest
|
|
89
|
-
// - AllowDecryptInAPI: true // Decrypted value can be sent to API clients
|
|
90
|
-
// - SendEncryptedValue: false // Whether to send encrypted ciphertext when AllowDecryptInAPI=false
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
**Example usage with encrypted field:**
|
|
94
|
-
```html
|
|
95
|
-
<!-- The component automatically detects encryption from entity metadata -->
|
|
96
|
-
<mj-form-field
|
|
97
|
-
[record]="userRecord"
|
|
98
|
-
[EditMode]="isEditing"
|
|
99
|
-
FieldName="SSN"
|
|
100
|
-
Type="textbox"
|
|
101
|
-
></mj-form-field>
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
The encrypted field UI includes:
|
|
105
|
-
- Lock icon (fa-lock) indicating the field is encrypted
|
|
106
|
-
- Eye toggle buttons (fa-eye / fa-eye-slash) for showing/hiding values
|
|
107
|
-
- Hint text for blind edit mode explaining the behavior
|
|
108
|
-
- Password-style masking for sensitive data entry
|
|
109
|
-
|
|
110
|
-
### MJLinkField
|
|
111
|
-
|
|
112
|
-
Specialized component for fields that link to other entity records:
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
<mj-link-field
|
|
116
|
-
[record]="myRecord"
|
|
117
|
-
FieldName="CustomerID"
|
|
118
|
-
[RecordName]="customerName"
|
|
119
|
-
LinkComponentType="Search"
|
|
120
|
-
></mj-link-field>
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
#### MJLinkField Input Properties
|
|
124
|
-
|
|
125
|
-
- `record` (BaseEntity, required): The entity record
|
|
126
|
-
- `FieldName` (string, required): The foreign key field name
|
|
127
|
-
- `RecordName` (string): Pre-populate with the linked record's name
|
|
128
|
-
- `LinkComponentType` ('Search' | 'Dropdown'): UI type for selecting records
|
|
129
|
-
|
|
130
|
-
### SectionLoaderComponent
|
|
131
|
-
|
|
132
|
-
Dynamically loads form sections registered with the MemberJunction class factory:
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
<mj-form-section
|
|
136
|
-
Entity="Customer"
|
|
137
|
-
Section="Details"
|
|
138
|
-
[record]="customerRecord"
|
|
139
|
-
[EditMode]="isEditing"
|
|
140
|
-
(LoadComplete)="onSectionLoaded()"
|
|
141
|
-
></mj-form-section>
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Base Classes
|
|
145
|
-
|
|
146
|
-
### BaseRecordComponent
|
|
147
|
-
|
|
148
|
-
The foundational class for all components that work with entity records:
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
import { BaseRecordComponent } from '@memberjunction/ng-base-forms';
|
|
152
|
-
|
|
153
|
-
@Component({
|
|
154
|
-
// ...
|
|
155
|
-
})
|
|
156
|
-
export class YourComponent extends BaseRecordComponent {
|
|
157
|
-
// Inherited properties:
|
|
158
|
-
// - record: BaseEntity
|
|
159
|
-
// - EditMode: boolean
|
|
160
|
-
// - UserCanEdit: boolean
|
|
161
|
-
// - UserCanDelete: boolean
|
|
162
|
-
// - IsFavorite: boolean
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### BaseFormSectionComponent
|
|
167
|
-
|
|
168
|
-
For creating reusable form sections that can be dynamically loaded:
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
import { BaseFormSectionComponent } from '@memberjunction/ng-base-forms';
|
|
172
|
-
import { RegisterClass } from '@memberjunction/global';
|
|
173
|
-
|
|
174
|
-
@Component({
|
|
175
|
-
template: `
|
|
176
|
-
<div class="form-section">
|
|
177
|
-
<!-- Your section UI here -->
|
|
178
|
-
</div>
|
|
179
|
-
`
|
|
180
|
-
})
|
|
181
|
-
@RegisterClass(BaseFormSectionComponent, 'Customer.Details')
|
|
182
|
-
export class CustomerDetailsSection extends BaseFormSectionComponent {
|
|
183
|
-
// Custom section logic
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### BaseFormComponent
|
|
188
|
-
|
|
189
|
-
For creating complete entity forms with full lifecycle management:
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
import { BaseFormComponent } from '@memberjunction/ng-base-forms';
|
|
193
|
-
import { RegisterClass } from '@memberjunction/global';
|
|
194
|
-
|
|
195
|
-
@Component({
|
|
196
|
-
template: `
|
|
197
|
-
<form>
|
|
198
|
-
<mj-tab-strip>
|
|
199
|
-
<mj-tab title="Details">
|
|
200
|
-
<mj-form-section Entity="Customer" Section="Details"
|
|
201
|
-
[record]="record" [EditMode]="EditMode">
|
|
202
|
-
</mj-form-section>
|
|
203
|
-
</mj-tab>
|
|
204
|
-
</mj-tab-strip>
|
|
205
|
-
</form>
|
|
206
|
-
`
|
|
207
|
-
})
|
|
208
|
-
@RegisterClass(BaseFormComponent, 'Customer')
|
|
209
|
-
export class CustomerFormComponent extends BaseFormComponent {
|
|
210
|
-
// Form-specific logic
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
## Core Features
|
|
215
|
-
|
|
216
|
-
### Edit Mode Management
|
|
217
|
-
|
|
218
|
-
```typescript
|
|
219
|
-
// Start editing
|
|
220
|
-
this.StartEditMode();
|
|
221
|
-
|
|
222
|
-
// Save changes (true = stop edit mode after save)
|
|
223
|
-
await this.SaveRecord(true);
|
|
224
|
-
|
|
225
|
-
// Cancel editing and revert changes
|
|
226
|
-
this.CancelEdit();
|
|
227
|
-
|
|
228
|
-
// Check if in edit mode
|
|
229
|
-
if (this.EditMode) {
|
|
230
|
-
// Show save/cancel buttons
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### Validation
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
// Validate the entire form
|
|
238
|
-
const validationResult = this.Validate();
|
|
239
|
-
if (!validationResult.Success) {
|
|
240
|
-
console.log('Validation errors:', validationResult.Errors);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Validate pending records
|
|
244
|
-
const pendingResults = this.ValidatePendingRecords();
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Permission Checking
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
// Check user permissions
|
|
251
|
-
if (this.UserCanEdit) {
|
|
252
|
-
this.StartEditMode();
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (this.UserCanDelete) {
|
|
256
|
-
// Show delete button
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Check field-level permissions
|
|
260
|
-
const canEditField = this.UserCanEditField('FieldName');
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Working with Related Records
|
|
264
|
-
|
|
265
|
-
```typescript
|
|
266
|
-
// Get view parameters for related entity
|
|
267
|
-
const viewParams = this.BuildRelationshipViewParamsByEntityName('Orders');
|
|
268
|
-
|
|
269
|
-
// Create new related record with pre-filled values
|
|
270
|
-
const newOrderValues = this.NewRecordValues('Orders');
|
|
271
|
-
newOrderValues.CustomerID = this.record.ID;
|
|
272
|
-
|
|
273
|
-
// Access pending records for transaction
|
|
274
|
-
const pendingOrders = this.PendingRecords.filter(r => r.Entity === 'Orders');
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### Tab Management
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
// Check active tab
|
|
281
|
-
if (this.IsCurrentTab('details')) {
|
|
282
|
-
// Load tab-specific data
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Handle tab selection
|
|
286
|
-
public onTabSelect(e: TabEvent) {
|
|
287
|
-
this.LoadTabData(e.title);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Tab configuration
|
|
291
|
-
tabs = [
|
|
292
|
-
{ title: 'Details', selected: true },
|
|
293
|
-
{ title: 'Orders', selected: false },
|
|
294
|
-
{ title: 'History', selected: false }
|
|
295
|
-
];
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### Favorites Management
|
|
299
|
-
|
|
300
|
-
```typescript
|
|
301
|
-
// Check if record is favorited
|
|
302
|
-
if (this.IsFavorite) {
|
|
303
|
-
// Show filled star icon
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Toggle favorite status
|
|
307
|
-
if (this.IsFavorite) {
|
|
308
|
-
await this.RemoveFavorite();
|
|
309
|
-
} else {
|
|
310
|
-
await this.MakeFavorite();
|
|
311
|
-
}
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### Record Dependencies
|
|
315
|
-
|
|
316
|
-
```typescript
|
|
317
|
-
// Check for dependencies before delete
|
|
318
|
-
const dependencies = await this.GetRecordDependencies();
|
|
319
|
-
if (dependencies.length > 0) {
|
|
320
|
-
// Show warning about dependent records
|
|
321
|
-
console.log(`Cannot delete: ${dependencies.length} dependent records found`);
|
|
322
|
-
}
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
## Advanced Usage
|
|
326
|
-
|
|
327
|
-
### Custom Field Rendering
|
|
328
|
-
|
|
329
|
-
Override default field rendering by creating custom components:
|
|
330
|
-
|
|
331
|
-
```typescript
|
|
332
|
-
@Component({
|
|
333
|
-
selector: 'custom-field',
|
|
334
|
-
template: `
|
|
335
|
-
<div class="custom-field">
|
|
336
|
-
<label>{{ field.DisplayName }}</label>
|
|
337
|
-
<custom-control [value]="value" (change)="onChange($event)">
|
|
338
|
-
</custom-control>
|
|
339
|
-
</div>
|
|
340
|
-
`
|
|
341
|
-
})
|
|
342
|
-
export class CustomFieldComponent {
|
|
343
|
-
@Input() field: EntityFieldInfo;
|
|
344
|
-
@Input() value: any;
|
|
345
|
-
@Output() valueChange = new EventEmitter<any>();
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
### Dynamic Form Section Registration
|
|
350
|
-
|
|
351
|
-
Register form sections to be dynamically loaded:
|
|
352
|
-
|
|
353
|
-
```typescript
|
|
354
|
-
// In your module or component
|
|
355
|
-
import { RegisterClass } from '@memberjunction/global';
|
|
356
|
-
|
|
357
|
-
@RegisterClass(BaseFormSectionComponent, 'Product.Inventory')
|
|
358
|
-
export class ProductInventorySection extends BaseFormSectionComponent {
|
|
359
|
-
// Section implementation
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Usage in template
|
|
363
|
-
<mj-form-section Entity="Product" Section="Inventory"
|
|
364
|
-
[record]="productRecord" [EditMode]="EditMode">
|
|
365
|
-
</mj-form-section>
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
### Transaction Management
|
|
369
|
-
|
|
370
|
-
Handle multiple related records in a single transaction:
|
|
371
|
-
|
|
372
|
-
```typescript
|
|
373
|
-
// Add records to pending transaction
|
|
374
|
-
this.AddPendingRecord(newOrderRecord, 'Orders');
|
|
375
|
-
this.AddPendingRecord(newOrderItemRecord, 'Order Items');
|
|
376
|
-
|
|
377
|
-
// Validate all pending records
|
|
378
|
-
const validationResults = this.ValidatePendingRecords();
|
|
379
|
-
if (validationResults.every(r => r.Success)) {
|
|
380
|
-
// Save all records in transaction
|
|
381
|
-
await this.SaveRecord(true);
|
|
382
|
-
}
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
## Module Configuration
|
|
386
|
-
|
|
387
|
-
The BaseFormsModule includes all necessary imports:
|
|
388
|
-
|
|
389
|
-
```typescript
|
|
390
|
-
import { BaseFormsModule } from '@memberjunction/ng-base-forms';
|
|
391
|
-
|
|
392
|
-
@NgModule({
|
|
393
|
-
imports: [
|
|
394
|
-
BaseFormsModule,
|
|
395
|
-
// Other imports...
|
|
396
|
-
]
|
|
397
|
-
})
|
|
398
|
-
export class YourModule { }
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
## Dependencies
|
|
402
|
-
|
|
403
|
-
- **Angular Core**: v18.0.2+
|
|
404
|
-
- **@memberjunction/core**: Core MJ functionality
|
|
405
|
-
- **@memberjunction/global**: Global utilities and class factory
|
|
406
|
-
- **@memberjunction/ng-shared**: Shared Angular services
|
|
407
|
-
- **@memberjunction/ng-tabstrip**: Tab management
|
|
408
|
-
- **@memberjunction/ng-link-directives**: Link handling
|
|
409
|
-
- **@memberjunction/ng-container-directives**: Container utilities
|
|
410
|
-
- **@memberjunction/ng-record-changes**: Change tracking
|
|
411
|
-
- **@memberjunction/ng-code-editor**: Code editing support
|
|
412
|
-
- **@progress/kendo-angular-\***: UI components
|
|
413
|
-
- **@memberjunction/ng-markdown**: Markdown rendering
|
|
414
|
-
- **rxjs**: Reactive programming
|
|
415
|
-
|
|
416
|
-
## Integration with MemberJunction
|
|
417
|
-
|
|
418
|
-
This package is designed to work seamlessly with the MemberJunction ecosystem:
|
|
419
|
-
|
|
420
|
-
- **Entity Metadata**: Automatically reads field definitions, relationships, and permissions
|
|
421
|
-
- **Class Factory**: Uses MJ's class factory for dynamic component loading
|
|
422
|
-
- **Validation**: Integrates with entity-level validation rules
|
|
423
|
-
- **Permissions**: Respects entity and field-level permissions
|
|
424
|
-
- **Transactions**: Supports MJ's transaction management for related records
|
|
425
|
-
|
|
426
|
-
## Best Practices
|
|
427
|
-
|
|
428
|
-
1. **Always use the class factory** for registering custom form components
|
|
429
|
-
2. **Leverage MJFormField** for automatic field rendering when possible
|
|
430
|
-
3. **Handle validation** at both field and form levels
|
|
431
|
-
4. **Check permissions** before allowing user actions
|
|
432
|
-
5. **Use transactions** when saving multiple related records
|
|
433
|
-
6. **Implement proper error handling** for save operations
|
|
434
|
-
7. **Follow Angular lifecycle** hooks for initialization and cleanup
|
|
435
|
-
|
|
436
|
-
## Building
|
|
437
|
-
|
|
438
|
-
This package uses Angular CLI for building:
|
|
439
|
-
|
|
440
|
-
```bash
|
|
441
|
-
# Build the package
|
|
442
|
-
npm run build
|
|
443
|
-
|
|
444
|
-
# The built package will be in the dist/ directory
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
## License
|
|
448
|
-
|
|
449
|
-
ISC
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { EventEmitter, AfterViewInit, Renderer2 } from '@angular/core';
|
|
2
|
-
import { BaseEntity, EntityFieldInfo } from '@memberjunction/core';
|
|
3
|
-
import { BaseRecordComponent } from './base-record-component';
|
|
4
|
-
import { BaseFormContext } from './base-form-context';
|
|
5
|
-
import { MarkdownComponent } from '@memberjunction/ng-markdown';
|
|
6
|
-
import * as i0 from "@angular/core";
|
|
7
|
-
/**
|
|
8
|
-
* This component is used to automatically generate a UI for any field in a given BaseEntity object. The CodeGen tool will generate forms and form sections that
|
|
9
|
-
* use this component. This component automatically determines the type of the field and generates the appropriate UI element for it. It is possible to use other
|
|
10
|
-
* elements to render a field as desired in a custom form, think of this component as a nice "base" component you can use for many cases, and you can create custom
|
|
11
|
-
* components for field rendering/editing when needed.
|
|
12
|
-
*/
|
|
13
|
-
export declare class MJFormField extends BaseRecordComponent implements AfterViewInit {
|
|
14
|
-
private renderer;
|
|
15
|
-
/**
|
|
16
|
-
* The record object that contains the field to be rendered. This object should be an instance of BaseEntity or a derived class.
|
|
17
|
-
*/
|
|
18
|
-
record: BaseEntity;
|
|
19
|
-
/**
|
|
20
|
-
* EditMode must be bound to the containing form's edit mode/state. When the form is in edit mode, the field will be rendered as an editable control (if not a read only field), otherwise the field will be rendered read-only.
|
|
21
|
-
*/
|
|
22
|
-
EditMode: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* The name of the field in the entity to be rendered.
|
|
25
|
-
*/
|
|
26
|
-
FieldName: string;
|
|
27
|
-
/**
|
|
28
|
-
* The type of control to be rendered for the field. The default is 'textbox'. Other possible values are 'textarea', 'numerictextbox', 'datepicker', 'checkbox', 'dropdownlist', 'combobox', 'code'.
|
|
29
|
-
*/
|
|
30
|
-
Type: 'textbox' | 'textarea' | 'numerictextbox' | 'datepicker' | 'checkbox' | 'dropdownlist' | 'combobox' | 'code';
|
|
31
|
-
/**
|
|
32
|
-
* Optional, the type of link field that should be shown. Email and URL fields will be rendered as hyperlinks, Record fields will be rendered as links to the record. The default is 'None'. Record Fields are only
|
|
33
|
-
* valid when the FieldName field is a foreign key field to another entity.
|
|
34
|
-
*/
|
|
35
|
-
LinkType: 'Email' | 'URL' | 'Record' | 'None';
|
|
36
|
-
/**
|
|
37
|
-
* Optional, when the field type is a linked field, you can specify if a search box is shown or a dropdown component is shown. The default is 'search'.
|
|
38
|
-
*/
|
|
39
|
-
LinkComponentType: 'Search' | 'Dropdown';
|
|
40
|
-
/**
|
|
41
|
-
* If set to false, the label for the field will not be shown. The default is true.
|
|
42
|
-
*/
|
|
43
|
-
ShowLabel: boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Form context containing all form-level state (filter, showEmptyFields, etc.)
|
|
46
|
-
*/
|
|
47
|
-
formContext?: BaseFormContext;
|
|
48
|
-
/**
|
|
49
|
-
* When true (default), the field will be hidden when it has no value and is in read-only mode.
|
|
50
|
-
* This helps reduce visual clutter by hiding empty fields.
|
|
51
|
-
*/
|
|
52
|
-
hideWhenEmptyInReadOnlyMode: boolean;
|
|
53
|
-
languages: import("@codemirror/language").LanguageDescription[];
|
|
54
|
-
private _displayName;
|
|
55
|
-
/**
|
|
56
|
-
* Display Name to show on the the control. By default, this is derived from the DisplayName in the entity field metadata, and can be overridden if desired by setting this property manually. Leave it empty to use the default.
|
|
57
|
-
*/
|
|
58
|
-
get DisplayName(): string;
|
|
59
|
-
set DisplayName(newValue: string);
|
|
60
|
-
/**
|
|
61
|
-
* Returns the display name with search highlighting applied if formContext.sectionFilter is set
|
|
62
|
-
*/
|
|
63
|
-
get HighlightedDisplayName(): string;
|
|
64
|
-
private escapeRegex;
|
|
65
|
-
get ExtendedType(): string;
|
|
66
|
-
private _possibleValues;
|
|
67
|
-
/**
|
|
68
|
-
* The possible values for the field. This is only used when the field is a dropdownlist or combobox. The possible values are derived from the EntityFieldValues in the entity field metadata.
|
|
69
|
-
* If the field is not a dropdownlist or combobox, this property is ignored. If you would like to specify a custom list of values, you can set this property manually.
|
|
70
|
-
*/
|
|
71
|
-
get PossibleValues(): string[];
|
|
72
|
-
set PossibleValues(newValue: string[]);
|
|
73
|
-
get Value(): any;
|
|
74
|
-
set Value(newValue: any);
|
|
75
|
-
ValueChange: EventEmitter<any>;
|
|
76
|
-
/**
|
|
77
|
-
* Returns true if the field is read only. This is determined by the ReadOnly property in the entity field metadata.
|
|
78
|
-
*/
|
|
79
|
-
get IsFieldReadOnly(): boolean;
|
|
80
|
-
get FieldInfo(): EntityFieldInfo;
|
|
81
|
-
/**
|
|
82
|
-
* Returns true if the field should be hidden (empty value in read-only mode with hideWhenEmptyInReadOnlyMode enabled)
|
|
83
|
-
*/
|
|
84
|
-
get shouldHideField(): boolean;
|
|
85
|
-
/**
|
|
86
|
-
* Returns true if the field is configured for encryption in the entity metadata
|
|
87
|
-
*/
|
|
88
|
-
get IsEncryptedField(): boolean;
|
|
89
|
-
/**
|
|
90
|
-
* Returns true if the field allows decrypted values to be shown in the API
|
|
91
|
-
*/
|
|
92
|
-
get AllowDecryptInAPI(): boolean;
|
|
93
|
-
/**
|
|
94
|
-
* Returns true if the field's current value is the encrypted sentinel value,
|
|
95
|
-
* indicating that the actual value is protected and cannot be shown.
|
|
96
|
-
*/
|
|
97
|
-
get IsValueEncryptedSentinel(): boolean;
|
|
98
|
-
/**
|
|
99
|
-
* Returns true if the field's current value should be treated as protected for display purposes.
|
|
100
|
-
* For encrypted fields where AllowDecryptInAPI=false, any non-empty value should be hidden.
|
|
101
|
-
*/
|
|
102
|
-
get IsValueProtected(): boolean;
|
|
103
|
-
/**
|
|
104
|
-
* Returns true if the encrypted field has a value that can be revealed (AllowDecryptInAPI=true)
|
|
105
|
-
*/
|
|
106
|
-
get CanRevealEncryptedValue(): boolean;
|
|
107
|
-
/**
|
|
108
|
-
* Controls whether the encrypted value is currently visible (for AllowDecryptInAPI=true fields)
|
|
109
|
-
*/
|
|
110
|
-
isEncryptedValueRevealed: boolean;
|
|
111
|
-
/**
|
|
112
|
-
* Controls whether the new value being typed is visible (for blind edit mode)
|
|
113
|
-
*/
|
|
114
|
-
isNewValueRevealed: boolean;
|
|
115
|
-
/**
|
|
116
|
-
* Toggles the visibility of the encrypted value
|
|
117
|
-
*/
|
|
118
|
-
toggleEncryptedValueVisibility(): void;
|
|
119
|
-
/**
|
|
120
|
-
* Toggles the visibility of the new value being typed (for blind edit mode)
|
|
121
|
-
*/
|
|
122
|
-
toggleNewValueVisibility(): void;
|
|
123
|
-
/**
|
|
124
|
-
* For encrypted fields in edit mode where AllowDecryptInAPI=false,
|
|
125
|
-
* we need a separate edit value that starts empty (user can't see existing value)
|
|
126
|
-
*/
|
|
127
|
-
private _encryptedEditValue;
|
|
128
|
-
/**
|
|
129
|
-
* Gets the value for editing encrypted fields.
|
|
130
|
-
* For AllowDecryptInAPI=false fields, returns empty string initially (user can't see existing value)
|
|
131
|
-
* For AllowDecryptInAPI=true fields, returns the actual value
|
|
132
|
-
*/
|
|
133
|
-
get EncryptedEditValue(): string;
|
|
134
|
-
/**
|
|
135
|
-
* Sets the encrypted edit value and updates the record
|
|
136
|
-
*/
|
|
137
|
-
set EncryptedEditValue(newValue: string);
|
|
138
|
-
/**
|
|
139
|
-
* Returns true if editing an encrypted field that doesn't allow viewing existing value
|
|
140
|
-
*/
|
|
141
|
-
get IsBlindEncryptedEdit(): boolean;
|
|
142
|
-
/**
|
|
143
|
-
* The masked display text for encrypted values (shows dots instead of actual value)
|
|
144
|
-
*/
|
|
145
|
-
readonly EncryptedDisplayMask = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
146
|
-
markdown: MarkdownComponent | undefined;
|
|
147
|
-
constructor(renderer: Renderer2);
|
|
148
|
-
ngAfterViewInit(): void;
|
|
149
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<MJFormField, never>;
|
|
150
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<MJFormField, "mj-form-field", never, { "record": { "alias": "record"; "required": false; }; "EditMode": { "alias": "EditMode"; "required": false; }; "FieldName": { "alias": "FieldName"; "required": false; }; "Type": { "alias": "Type"; "required": false; }; "LinkType": { "alias": "LinkType"; "required": false; }; "LinkComponentType": { "alias": "LinkComponentType"; "required": false; }; "ShowLabel": { "alias": "ShowLabel"; "required": false; }; "formContext": { "alias": "formContext"; "required": false; }; "hideWhenEmptyInReadOnlyMode": { "alias": "hideWhenEmptyInReadOnlyMode"; "required": false; }; "DisplayName": { "alias": "DisplayName"; "required": false; }; "PossibleValues": { "alias": "PossibleValues"; "required": false; }; "Value": { "alias": "Value"; "required": false; }; }, { "ValueChange": "ValueChange"; }, never, never, false, never>;
|
|
151
|
-
}
|
|
152
|
-
//# sourceMappingURL=base-field-component.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"base-field-component.d.ts","sourceRoot":"","sources":["../../src/lib/base-field-component.ts"],"names":[],"mappings":"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"}
|