@memberjunction/ng-base-types 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.
- package/README.md +268 -63
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Foundational types and base classes for Angular components in the MemberJunction ecosystem, providing common functionality and type definitions.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
- Common event
|
|
10
|
-
-
|
|
7
|
+
This package provides essential building blocks for Angular applications using MemberJunction:
|
|
8
|
+
- **BaseAngularComponent**: Abstract base class providing standardized provider management
|
|
9
|
+
- **Event Types**: Common event definitions for form component coordination
|
|
10
|
+
- **Type Safety**: Full TypeScript support with strict typing
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -15,104 +15,309 @@ Foundational types and base classes for Angular components in the MemberJunction
|
|
|
15
15
|
npm install @memberjunction/ng-base-types
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
### Abstract Base Component
|
|
21
|
+
- Centralized provider management for data access
|
|
22
|
+
- Automatic provider inheritance throughout component trees
|
|
23
|
+
- Support for multiple concurrent API connections
|
|
24
|
+
|
|
25
|
+
### Form Event System
|
|
26
|
+
- Standardized event types for form component communication
|
|
27
|
+
- Support for save/delete operations coordination
|
|
28
|
+
- Pending changes management
|
|
29
|
+
|
|
30
|
+
### TypeScript Support
|
|
31
|
+
- Full type definitions for all exports
|
|
32
|
+
- Strict mode compatible
|
|
33
|
+
- Enhanced IDE intellisense
|
|
34
|
+
|
|
35
|
+
## API Documentation
|
|
19
36
|
|
|
20
37
|
### BaseAngularComponent
|
|
21
38
|
|
|
22
|
-
Abstract base class
|
|
39
|
+
Abstract base class that all MemberJunction Angular components should extend:
|
|
23
40
|
|
|
24
41
|
```typescript
|
|
25
42
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
43
|
+
import { Component, OnInit } from '@angular/core';
|
|
26
44
|
|
|
27
45
|
@Component({
|
|
28
|
-
selector: '
|
|
29
|
-
templateUrl: './
|
|
30
|
-
styleUrls: ['./your.component.css']
|
|
46
|
+
selector: 'my-component',
|
|
47
|
+
templateUrl: './my-component.html'
|
|
31
48
|
})
|
|
32
|
-
export class
|
|
33
|
-
// Your component implementation
|
|
34
|
-
|
|
49
|
+
export class MyComponent extends BaseAngularComponent implements OnInit {
|
|
35
50
|
ngOnInit() {
|
|
36
|
-
// Access
|
|
51
|
+
// Access the metadata provider
|
|
37
52
|
const metadata = this.ProviderToUse;
|
|
38
53
|
|
|
39
|
-
//
|
|
54
|
+
// Use RunView functionality
|
|
40
55
|
const viewProvider = this.RunViewToUse;
|
|
56
|
+
|
|
57
|
+
// Execute queries
|
|
58
|
+
const queryProvider = this.RunQueryToUse;
|
|
59
|
+
|
|
60
|
+
// Run reports
|
|
61
|
+
const reportProvider = this.RunReportToUse;
|
|
41
62
|
}
|
|
42
63
|
}
|
|
43
64
|
```
|
|
44
65
|
|
|
45
|
-
|
|
66
|
+
#### Properties
|
|
67
|
+
|
|
68
|
+
| Property | Type | Description |
|
|
69
|
+
|----------|------|-------------|
|
|
70
|
+
| `Provider` | `IMetadataProvider \| null` | Optional custom provider instance. If not specified, uses the default global provider. |
|
|
71
|
+
|
|
72
|
+
#### Getter Methods
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
74
|
+
| Method | Return Type | Description |
|
|
75
|
+
|--------|-------------|-------------|
|
|
76
|
+
| `ProviderToUse` | `IMetadataProvider` | Returns the Provider if specified, otherwise returns the default Metadata.Provider |
|
|
77
|
+
| `RunViewToUse` | `IRunViewProvider` | Returns the provider cast as IRunViewProvider for running views |
|
|
78
|
+
| `RunQueryToUse` | `IRunQueryProvider` | Returns the provider cast as IRunQueryProvider for executing queries |
|
|
79
|
+
| `RunReportToUse` | `IRunReportProvider` | Returns the provider cast as IRunReportProvider for running reports |
|
|
53
80
|
|
|
54
81
|
### Form Component Events
|
|
55
82
|
|
|
56
|
-
|
|
83
|
+
#### BaseFormComponentEventCodes
|
|
84
|
+
|
|
85
|
+
Constants for event type identification:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const BaseFormComponentEventCodes = {
|
|
89
|
+
BASE_CODE: 'BaseFormComponent_Event',
|
|
90
|
+
EDITING_COMPLETE: 'EDITING_COMPLETE',
|
|
91
|
+
REVERT_PENDING_CHANGES: 'REVERT_PENDING_CHANGES',
|
|
92
|
+
POPULATE_PENDING_RECORDS: 'POPULATE_PENDING_RECORDS'
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Event Classes
|
|
97
|
+
|
|
98
|
+
##### BaseFormComponentEvent
|
|
99
|
+
|
|
100
|
+
Base class for all form component events:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
class BaseFormComponentEvent {
|
|
104
|
+
subEventCode: string; // Event type identifier
|
|
105
|
+
elementRef: any; // Reference to the emitting element
|
|
106
|
+
returnValue: any; // Optional return value
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
##### FormEditingCompleteEvent
|
|
111
|
+
|
|
112
|
+
Specialized event emitted when form editing is complete:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
class FormEditingCompleteEvent extends BaseFormComponentEvent {
|
|
116
|
+
subEventCode: string = BaseFormComponentEventCodes.EDITING_COMPLETE;
|
|
117
|
+
pendingChanges: PendingRecordItem[] = [];
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
##### PendingRecordItem
|
|
122
|
+
|
|
123
|
+
Represents a record pending save or delete:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
class PendingRecordItem {
|
|
127
|
+
entityObject: BaseEntity; // The entity to be processed
|
|
128
|
+
action: 'save' | 'delete' = 'save'; // Action to perform
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Usage Examples
|
|
133
|
+
|
|
134
|
+
### Implementing a Component with Custom Provider
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { Component, OnInit } from '@angular/core';
|
|
138
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
139
|
+
import { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';
|
|
140
|
+
|
|
141
|
+
@Component({
|
|
142
|
+
selector: 'app-custom-provider',
|
|
143
|
+
template: `
|
|
144
|
+
<div>
|
|
145
|
+
<child-component [Provider]="customProvider"></child-component>
|
|
146
|
+
</div>
|
|
147
|
+
`
|
|
148
|
+
})
|
|
149
|
+
export class CustomProviderComponent extends BaseAngularComponent implements OnInit {
|
|
150
|
+
customProvider: GraphQLDataProvider;
|
|
151
|
+
|
|
152
|
+
ngOnInit() {
|
|
153
|
+
// Create a custom provider for a different API endpoint
|
|
154
|
+
this.customProvider = new GraphQLDataProvider({
|
|
155
|
+
endpoint: 'https://api.example.com/graphql',
|
|
156
|
+
headers: {
|
|
157
|
+
'Authorization': 'Bearer YOUR_TOKEN'
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Handling Form Events
|
|
57
165
|
|
|
58
166
|
```typescript
|
|
167
|
+
import { Component, EventEmitter, Output } from '@angular/core';
|
|
59
168
|
import {
|
|
60
|
-
|
|
169
|
+
BaseAngularComponent,
|
|
61
170
|
BaseFormComponentEvent,
|
|
171
|
+
BaseFormComponentEventCodes,
|
|
62
172
|
FormEditingCompleteEvent,
|
|
63
173
|
PendingRecordItem
|
|
64
174
|
} from '@memberjunction/ng-base-types';
|
|
65
175
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
176
|
+
@Component({
|
|
177
|
+
selector: 'app-form-handler',
|
|
178
|
+
template: `...`
|
|
179
|
+
})
|
|
180
|
+
export class FormHandlerComponent extends BaseAngularComponent {
|
|
181
|
+
@Output() formEvent = new EventEmitter<BaseFormComponentEvent>();
|
|
182
|
+
|
|
183
|
+
async handleFormSubmit(entities: BaseEntity[]) {
|
|
184
|
+
// Create the event
|
|
185
|
+
const event = new FormEditingCompleteEvent();
|
|
186
|
+
|
|
187
|
+
// Add pending changes
|
|
188
|
+
event.pendingChanges = entities.map(entity => ({
|
|
189
|
+
entityObject: entity,
|
|
190
|
+
action: 'save' as const
|
|
191
|
+
}));
|
|
192
|
+
|
|
193
|
+
// Emit the event
|
|
194
|
+
this.formEvent.emit(event);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
onFormEvent(event: BaseFormComponentEvent) {
|
|
198
|
+
switch (event.subEventCode) {
|
|
199
|
+
case BaseFormComponentEventCodes.EDITING_COMPLETE:
|
|
200
|
+
const editEvent = event as FormEditingCompleteEvent;
|
|
201
|
+
this.processPendingChanges(editEvent.pendingChanges);
|
|
202
|
+
break;
|
|
203
|
+
|
|
204
|
+
case BaseFormComponentEventCodes.REVERT_PENDING_CHANGES:
|
|
205
|
+
this.revertChanges();
|
|
206
|
+
break;
|
|
207
|
+
|
|
208
|
+
case BaseFormComponentEventCodes.POPULATE_PENDING_RECORDS:
|
|
209
|
+
this.populateRecords();
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private async processPendingChanges(changes: PendingRecordItem[]) {
|
|
215
|
+
for (const item of changes) {
|
|
216
|
+
try {
|
|
73
217
|
if (item.action === 'save') {
|
|
74
|
-
|
|
75
|
-
item.entityObject.Save();
|
|
218
|
+
await item.entityObject.Save();
|
|
76
219
|
} else if (item.action === 'delete') {
|
|
77
|
-
|
|
78
|
-
item.entityObject.Delete();
|
|
220
|
+
await item.entityObject.Delete();
|
|
79
221
|
}
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// Handle reverting changes
|
|
85
|
-
break;
|
|
86
|
-
|
|
87
|
-
case BaseFormComponentEventCodes.POPULATE_PENDING_RECORDS:
|
|
88
|
-
// Handle populating pending records
|
|
89
|
-
break;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error(`Failed to ${item.action} entity:`, error);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
90
226
|
}
|
|
91
227
|
}
|
|
92
|
-
|
|
93
|
-
// Create and emit a form event
|
|
94
|
-
const event = new FormEditingCompleteEvent();
|
|
95
|
-
event.pendingChanges = [
|
|
96
|
-
{ entityObject: myEntity, action: 'save' }
|
|
97
|
-
];
|
|
98
|
-
someEventEmitter.emit(event);
|
|
99
228
|
```
|
|
100
229
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
You can customize the data providers used by components by setting the Provider input:
|
|
230
|
+
### Using Multiple Providers in an Application
|
|
104
231
|
|
|
105
232
|
```typescript
|
|
233
|
+
import { Component } from '@angular/core';
|
|
234
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
106
235
|
import { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';
|
|
107
236
|
|
|
108
|
-
|
|
109
|
-
|
|
237
|
+
@Component({
|
|
238
|
+
selector: 'app-multi-tenant',
|
|
239
|
+
template: `
|
|
240
|
+
<div class="tenant-a">
|
|
241
|
+
<user-list [Provider]="tenantAProvider"></user-list>
|
|
242
|
+
</div>
|
|
243
|
+
<div class="tenant-b">
|
|
244
|
+
<user-list [Provider]="tenantBProvider"></user-list>
|
|
245
|
+
</div>
|
|
246
|
+
`
|
|
247
|
+
})
|
|
248
|
+
export class MultiTenantComponent extends BaseAngularComponent {
|
|
249
|
+
tenantAProvider = new GraphQLDataProvider({
|
|
250
|
+
endpoint: 'https://tenant-a.example.com/graphql'
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
tenantBProvider = new GraphQLDataProvider({
|
|
254
|
+
endpoint: 'https://tenant-b.example.com/graphql'
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Dependencies
|
|
260
|
+
|
|
261
|
+
### Runtime Dependencies
|
|
262
|
+
- `@memberjunction/core`: Core MemberJunction functionality
|
|
263
|
+
- `@memberjunction/core-entities`: Entity definitions
|
|
264
|
+
- `@memberjunction/global`: Global utilities
|
|
265
|
+
- `tslib`: TypeScript runtime helpers
|
|
266
|
+
|
|
267
|
+
### Peer Dependencies
|
|
268
|
+
- `@angular/common`: ^18.0.2
|
|
269
|
+
- `@angular/core`: ^18.0.2
|
|
270
|
+
|
|
271
|
+
## Build Configuration
|
|
272
|
+
|
|
273
|
+
This package uses Angular's `ngc` compiler for building:
|
|
110
274
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
endpoint: 'https://your-custom-endpoint/graphql',
|
|
114
|
-
// other configuration options
|
|
115
|
-
});
|
|
275
|
+
```bash
|
|
276
|
+
npm run build
|
|
116
277
|
```
|
|
117
278
|
|
|
118
|
-
|
|
279
|
+
The package is configured with:
|
|
280
|
+
- No side effects for better tree-shaking
|
|
281
|
+
- Full TypeScript declarations
|
|
282
|
+
- Angular Ivy compatibility
|
|
283
|
+
|
|
284
|
+
## Integration with MemberJunction
|
|
285
|
+
|
|
286
|
+
This package is designed to work seamlessly with other MemberJunction packages:
|
|
287
|
+
|
|
288
|
+
- **@memberjunction/core**: Provides the entity and provider interfaces
|
|
289
|
+
- **@memberjunction/graphql-dataprovider**: Default data provider implementation
|
|
290
|
+
- **@memberjunction/ng-\***: Other Angular-specific packages that extend BaseAngularComponent
|
|
291
|
+
|
|
292
|
+
## Best Practices
|
|
293
|
+
|
|
294
|
+
1. **Always extend BaseAngularComponent** for MemberJunction Angular components
|
|
295
|
+
2. **Use the provider getters** instead of directly accessing Metadata or RunView classes
|
|
296
|
+
3. **Emit standardized events** using the provided event classes for better interoperability
|
|
297
|
+
4. **Handle errors appropriately** when processing pending changes
|
|
298
|
+
5. **Pass providers down the component tree** when working with multiple API endpoints
|
|
299
|
+
|
|
300
|
+
## Migration Guide
|
|
301
|
+
|
|
302
|
+
If upgrading from a previous version:
|
|
303
|
+
|
|
304
|
+
1. Update all components to extend `BaseAngularComponent`
|
|
305
|
+
2. Replace direct `Metadata` usage with `this.ProviderToUse`
|
|
306
|
+
3. Update event handling to use the standardized event types
|
|
307
|
+
4. Remove any custom provider management code in favor of the built-in system
|
|
308
|
+
|
|
309
|
+
## Known Issues
|
|
310
|
+
|
|
311
|
+
- The `RunQueryToUse` and `RunReportToUse` getters in the current implementation have incomplete type casting. Ensure your provider implements all required interfaces.
|
|
312
|
+
|
|
313
|
+
## Contributing
|
|
314
|
+
|
|
315
|
+
When contributing to this package:
|
|
316
|
+
1. Maintain backward compatibility
|
|
317
|
+
2. Add tests for new functionality
|
|
318
|
+
3. Update this README with new features
|
|
319
|
+
4. Follow the MemberJunction coding standards
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
ISC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-base-types",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.44.0",
|
|
4
4
|
"description": "MemberJunction: Simple types that are used across many generic Angular UI components for coordination",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"@angular/core": "18.0.2"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@memberjunction/core-entities": "2.
|
|
27
|
-
"@memberjunction/global": "2.
|
|
28
|
-
"@memberjunction/core": "2.
|
|
26
|
+
"@memberjunction/core-entities": "2.44.0",
|
|
27
|
+
"@memberjunction/global": "2.44.0",
|
|
28
|
+
"@memberjunction/core": "2.44.0",
|
|
29
29
|
"tslib": "^2.3.0"
|
|
30
30
|
},
|
|
31
31
|
"sideEffects": false
|