@smallpearl/ngx-helper 0.33.23 → 0.33.26
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/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs +152 -19
- package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs.map +1 -1
- package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs.map +1 -1
- package/mat-entity-crud/src/form-view-host.component.d.ts +5 -0
- package/mat-entity-crud/src/mat-entity-crud-form-base.d.ts +42 -4
- package/mat-entity-crud/src/mat-entity-crud-internal-types.d.ts +14 -0
- package/mat-entity-crud/src/mat-entity-crud-types.d.ts +20 -1
- package/mat-entity-crud/src/mat-entity-crud.component.d.ts +4 -0
- package/mat-entity-list/src/mat-entity-list.component.d.ts +1 -1
- package/package.json +11 -11
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i1 from '@angular/common/http';
|
|
2
|
-
import { HttpContextToken, HttpParams, HttpContext } from '@angular/common/http';
|
|
2
|
+
import { HttpContextToken, HttpParams, HttpContext, HttpClient } from '@angular/common/http';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { InjectionToken, inject, input, computed, signal, viewChild, ViewContainerRef, Component, ChangeDetectionStrategy, viewChildren, EventEmitter, effect, ContentChildren, Output, ChangeDetectorRef } from '@angular/core';
|
|
5
5
|
import * as i4 from '@angular/common';
|
|
@@ -31,6 +31,7 @@ import { Observable, of, Subscription, tap, switchMap, firstValueFrom, map, catc
|
|
|
31
31
|
import * as i1$1 from '@angular/material/toolbar';
|
|
32
32
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
33
33
|
import { setServerErrorsAsFormErrors } from '@smallpearl/ngx-helper/forms';
|
|
34
|
+
import { sideloadToComposite } from '@smallpearl/ngx-helper/sideload';
|
|
34
35
|
|
|
35
36
|
const SP_MAT_ENTITY_CRUD_HTTP_CONTEXT = new HttpContextToken(() => ({
|
|
36
37
|
entityName: '',
|
|
@@ -120,6 +121,16 @@ class FormViewHostComponent {
|
|
|
120
121
|
this.params.set(params);
|
|
121
122
|
this.createClientView();
|
|
122
123
|
}
|
|
124
|
+
// BEGIN SPMatEntityCrudCreateEditBridge METHODS //
|
|
125
|
+
getEntityName() {
|
|
126
|
+
return this.entityCrudComponentBase().getEntityName();
|
|
127
|
+
}
|
|
128
|
+
getIdKey() {
|
|
129
|
+
return this.entityCrudComponentBase().getIdKey();
|
|
130
|
+
}
|
|
131
|
+
getEntityUrl(entityId) {
|
|
132
|
+
return this.entityCrudComponentBase().getEntityUrl(entityId);
|
|
133
|
+
}
|
|
123
134
|
close(cancel) {
|
|
124
135
|
this.entityCrudComponentBase().closeCreateEdit(cancel);
|
|
125
136
|
// destroy the client's form component
|
|
@@ -150,6 +161,10 @@ class FormViewHostComponent {
|
|
|
150
161
|
?.update(id, entityValue)
|
|
151
162
|
.pipe(tap(() => this.close(false)));
|
|
152
163
|
}
|
|
164
|
+
loadEntity(id, params) {
|
|
165
|
+
return this.entityCrudComponentBase().loadEntity(id, params);
|
|
166
|
+
}
|
|
167
|
+
// END SPMatEntityCrudCreateEditBridge METHODS //
|
|
153
168
|
/**
|
|
154
169
|
* Creates the client view provided via template
|
|
155
170
|
*/
|
|
@@ -184,14 +199,30 @@ class FormViewHostComponent {
|
|
|
184
199
|
}
|
|
185
200
|
/** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: FormViewHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
186
201
|
/** @nocollapse */ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: FormViewHostComponent, isStandalone: true, selector: "sp-create-edit-entity-host", inputs: { entityCrudComponentBase: { classPropertyName: "entityCrudComponentBase", publicName: "entityCrudComponentBase", isSignal: true, isRequired: true, transformFunction: null }, clientViewTemplate: { classPropertyName: "clientViewTemplate", publicName: "clientViewTemplate", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "vc", first: true, predicate: ["clientFormContainer"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: `
|
|
187
|
-
<div
|
|
188
|
-
|
|
202
|
+
<div
|
|
203
|
+
[class]="
|
|
204
|
+
'sp-mat-crud-form-wrapper ' +
|
|
205
|
+
entityCrudComponentBase().getFormPaneWrapperClass()
|
|
206
|
+
"
|
|
207
|
+
spHostBusyWheel="formBusyWheel"
|
|
208
|
+
*transloco="let t"
|
|
209
|
+
>
|
|
210
|
+
<div
|
|
211
|
+
[class]="
|
|
212
|
+
'sp-mat-crud-form-content ' +
|
|
213
|
+
entityCrudComponentBase().getFormPaneContentClass()
|
|
214
|
+
"
|
|
215
|
+
>
|
|
189
216
|
<div class="create-edit-topbar">
|
|
190
217
|
<div class="title">
|
|
191
218
|
@if (title()) {
|
|
192
|
-
|
|
219
|
+
{{ title() | async }}
|
|
193
220
|
} @else {
|
|
194
|
-
|
|
221
|
+
{{
|
|
222
|
+
t('spMatEntityCrud.' + (entity() ? 'editItem' : 'newItem'), {
|
|
223
|
+
item: (this._itemLabel() | async)
|
|
224
|
+
})
|
|
225
|
+
}}
|
|
195
226
|
}
|
|
196
227
|
</div>
|
|
197
228
|
<div class="spacer"></div>
|
|
@@ -217,14 +248,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
|
|
|
217
248
|
TranslocoModule,
|
|
218
249
|
SPMatHostBusyWheelDirective,
|
|
219
250
|
], selector: 'sp-create-edit-entity-host', template: `
|
|
220
|
-
<div
|
|
221
|
-
|
|
251
|
+
<div
|
|
252
|
+
[class]="
|
|
253
|
+
'sp-mat-crud-form-wrapper ' +
|
|
254
|
+
entityCrudComponentBase().getFormPaneWrapperClass()
|
|
255
|
+
"
|
|
256
|
+
spHostBusyWheel="formBusyWheel"
|
|
257
|
+
*transloco="let t"
|
|
258
|
+
>
|
|
259
|
+
<div
|
|
260
|
+
[class]="
|
|
261
|
+
'sp-mat-crud-form-content ' +
|
|
262
|
+
entityCrudComponentBase().getFormPaneContentClass()
|
|
263
|
+
"
|
|
264
|
+
>
|
|
222
265
|
<div class="create-edit-topbar">
|
|
223
266
|
<div class="title">
|
|
224
267
|
@if (title()) {
|
|
225
|
-
|
|
268
|
+
{{ title() | async }}
|
|
226
269
|
} @else {
|
|
227
|
-
|
|
270
|
+
{{
|
|
271
|
+
t('spMatEntityCrud.' + (entity() ? 'editItem' : 'newItem'), {
|
|
272
|
+
item: (this._itemLabel() | async)
|
|
273
|
+
})
|
|
274
|
+
}}
|
|
228
275
|
}
|
|
229
276
|
</div>
|
|
230
277
|
<div class="spacer"></div>
|
|
@@ -662,6 +709,16 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
|
|
|
662
709
|
refresh(force = false) {
|
|
663
710
|
this.spEntitiesList()?.refresh(force);
|
|
664
711
|
}
|
|
712
|
+
// BEGIN SPMatEntityCrudComponentBase METHODS //
|
|
713
|
+
getEntityName() {
|
|
714
|
+
return this.entityName();
|
|
715
|
+
}
|
|
716
|
+
getEntityNamePlural() {
|
|
717
|
+
return this._entityNamePlural();
|
|
718
|
+
}
|
|
719
|
+
getIdKey() {
|
|
720
|
+
return this.idKey();
|
|
721
|
+
}
|
|
665
722
|
closeCreateEdit(cancelled) {
|
|
666
723
|
this.createEditViewActive.set(false);
|
|
667
724
|
this.entityViewPaneActivated.emit({
|
|
@@ -733,6 +790,22 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
|
|
|
733
790
|
}
|
|
734
791
|
}));
|
|
735
792
|
}
|
|
793
|
+
loadEntity(id, params) {
|
|
794
|
+
const crudOpFn = this.crudOpFn();
|
|
795
|
+
if (crudOpFn) {
|
|
796
|
+
return crudOpFn('get', id, undefined, this);
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
const httpParams = params instanceof HttpParams
|
|
800
|
+
? params
|
|
801
|
+
: new HttpParams({ fromString: params });
|
|
802
|
+
return this.http.get(this.getEntityUrl(id), {
|
|
803
|
+
context: this.getCrudReqHttpContext('retrieve'),
|
|
804
|
+
params: httpParams,
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
// END SPMatEntityCrudComponentBase METHODS //
|
|
736
809
|
/**
|
|
737
810
|
* Thunk these methods to the internal <sp-mat-entity-list> component.
|
|
738
811
|
*/
|
|
@@ -834,10 +907,11 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
|
|
|
834
907
|
return;
|
|
835
908
|
}
|
|
836
909
|
}
|
|
837
|
-
this.doEntityAction(entity[this.idKey()], verb, httpRequestParameters.params || new HttpParams(), httpRequestParameters.body)
|
|
910
|
+
this.doEntityAction(entity[this.idKey()], verb, httpRequestParameters.params || new HttpParams(), httpRequestParameters.body)
|
|
911
|
+
.pipe(tap((response) => {
|
|
838
912
|
const successMessage = actionItem?.successMessage ||
|
|
839
913
|
this.transloco.translate('spMatEntityCrud.done');
|
|
840
|
-
this.snackBar.open(successMessage ||
|
|
914
|
+
this.snackBar.open(successMessage || 'Done');
|
|
841
915
|
}), catchError((error) => {
|
|
842
916
|
/**
|
|
843
917
|
* If an errorMessage is specified in the actionItem, display it.
|
|
@@ -849,7 +923,8 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
|
|
|
849
923
|
return EMPTY;
|
|
850
924
|
}
|
|
851
925
|
return throwError(() => error);
|
|
852
|
-
}))
|
|
926
|
+
}))
|
|
927
|
+
.subscribe();
|
|
853
928
|
}
|
|
854
929
|
onCreate(event) {
|
|
855
930
|
// If newItemLink() has not been provided, check if createEditFormTemplate
|
|
@@ -1053,7 +1128,8 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
|
|
|
1053
1128
|
// be an array of HttpContextToken key, value pairs.
|
|
1054
1129
|
contextParamToHttpContext(context, crudHttpReqContext);
|
|
1055
1130
|
}
|
|
1056
|
-
else if (typeof crudHttpReqContext === 'object' &&
|
|
1131
|
+
else if (typeof crudHttpReqContext === 'object' &&
|
|
1132
|
+
op &&
|
|
1057
1133
|
Object.keys(crudHttpReqContext).find((k) => k === op)) {
|
|
1058
1134
|
// HttpContext specific to this crud operation, 'create'|'retrieve'|'update'|'delete'
|
|
1059
1135
|
contextParamToHttpContext(context, crudHttpReqContext[op]);
|
|
@@ -1678,22 +1754,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
|
|
|
1678
1754
|
* ```
|
|
1679
1755
|
*
|
|
1680
1756
|
* 3. If you form's value requires manipulation before being sent to the
|
|
1681
|
-
* server, override getFormValue() method and do it there before returning
|
|
1757
|
+
* server, override `getFormValue()` method and do it there before returning
|
|
1682
1758
|
* the modified values.
|
|
1683
1759
|
*
|
|
1684
1760
|
* 4. Wire up the form in the template as:
|
|
1685
1761
|
*
|
|
1686
1762
|
* ```
|
|
1763
|
+
* @if (loadEntity$ | async) {
|
|
1687
1764
|
* <form [formGroup]='form'.. (ngSubmit)="onSubmit()">
|
|
1688
1765
|
* <button type="submit">Submit</button>
|
|
1689
1766
|
* </form>
|
|
1767
|
+
* } @else {
|
|
1768
|
+
* <div>Loading...</div>
|
|
1769
|
+
* }
|
|
1690
1770
|
* ```
|
|
1771
|
+
* Here `loadEntity$` is an Observable<boolean> that upon emission of `true`
|
|
1772
|
+
* indicates that the entity has been loaded from server (in case of edit)
|
|
1773
|
+
* and the form is ready to be displayed. Note that if the full entity was
|
|
1774
|
+
* passed in the `entity` input property, then no server load is necessary
|
|
1775
|
+
* and the form will be created immediately.
|
|
1776
|
+
*
|
|
1777
|
+
* 5. If the entity shape required by the form requires additional parameters
|
|
1778
|
+
* to be loaded from server, initialize `entity` property with it's id.
|
|
1779
|
+
* Then override the `getLoadEntityParams()` method to return the additional
|
|
1780
|
+
* load parameters. The parameters returned by this method will be
|
|
1781
|
+
* passed to the `loadEntity()` method of the bridge interface.
|
|
1691
1782
|
*/
|
|
1692
1783
|
class SPMatEntityCrudFormBase {
|
|
1693
1784
|
_form = signal(undefined);
|
|
1694
1785
|
entity = input.required();
|
|
1695
1786
|
bridge = input.required();
|
|
1696
1787
|
params = input();
|
|
1788
|
+
loadEntity$;
|
|
1789
|
+
_entity = signal(undefined);
|
|
1697
1790
|
sub$ = new Subscription();
|
|
1698
1791
|
// Force typecast to TFormGroup so that we can use it in the template
|
|
1699
1792
|
// without having to use the non-nullable operator ! with every reference
|
|
@@ -1701,9 +1794,10 @@ class SPMatEntityCrudFormBase {
|
|
|
1701
1794
|
// method after the form is created. And if form() is not set, then there
|
|
1702
1795
|
// will be errors while loading the form in the template.
|
|
1703
1796
|
form = computed(() => this._form());
|
|
1704
|
-
crudConfig = getEntityCrudConfig();
|
|
1797
|
+
// crudConfig = getEntityCrudConfig();
|
|
1705
1798
|
transloco = inject(TranslocoService);
|
|
1706
1799
|
cdr = inject(ChangeDetectorRef);
|
|
1800
|
+
http = inject(HttpClient);
|
|
1707
1801
|
canCancelEdit = () => {
|
|
1708
1802
|
return this._canCancelEdit();
|
|
1709
1803
|
};
|
|
@@ -1715,12 +1809,50 @@ class SPMatEntityCrudFormBase {
|
|
|
1715
1809
|
return true;
|
|
1716
1810
|
}
|
|
1717
1811
|
ngOnInit() {
|
|
1718
|
-
this.
|
|
1719
|
-
|
|
1812
|
+
this.loadEntity$ = (typeof this.entity() === 'object' || this.entity() === undefined
|
|
1813
|
+
? new Observable((subscriber) => {
|
|
1814
|
+
subscriber.next(this.entity());
|
|
1815
|
+
subscriber.complete();
|
|
1816
|
+
})
|
|
1817
|
+
: this.bridge()?.loadEntity(this.entity(), this.getLoadEntityParams())).pipe(map((resp) => {
|
|
1818
|
+
const compositeEntity = this.getEntityFromLoadResponse(resp);
|
|
1819
|
+
this._entity.set(compositeEntity);
|
|
1820
|
+
this._form.set(this.createForm(compositeEntity));
|
|
1821
|
+
this.bridge()?.registerCanCancelEditCallback(this.canCancelEdit);
|
|
1822
|
+
return true;
|
|
1823
|
+
}));
|
|
1720
1824
|
}
|
|
1721
1825
|
ngOnDestroy() {
|
|
1722
1826
|
this.sub$.unsubscribe();
|
|
1723
1827
|
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Additional parameters for loading the entity, in case this.entity() value
|
|
1830
|
+
* is of type TEntity[IdKey].
|
|
1831
|
+
* @returns
|
|
1832
|
+
*/
|
|
1833
|
+
getLoadEntityParams() {
|
|
1834
|
+
return '';
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Return the TEntity object from the response returned by the
|
|
1838
|
+
* loadEntity() method of the bridge. Typically entity load return the actual
|
|
1839
|
+
* entity object itself. In some cases, where response is sideloaded, the
|
|
1840
|
+
* default implementation here uses the `sideloadToComposite()` utility to
|
|
1841
|
+
* extract the entity from the response after merging (inplace) the
|
|
1842
|
+
* sideloaded data into a composite.
|
|
1843
|
+
*
|
|
1844
|
+
* If you have a different response shape, override this method to
|
|
1845
|
+
* extract the TEntity object from the response.
|
|
1846
|
+
* @param resp
|
|
1847
|
+
* @returns
|
|
1848
|
+
*/
|
|
1849
|
+
getEntityFromLoadResponse(resp) {
|
|
1850
|
+
if (!resp) {
|
|
1851
|
+
return undefined;
|
|
1852
|
+
}
|
|
1853
|
+
const sideloaded = sideloadToComposite(resp, this.bridge().getEntityName(), this.bridge().getIdKey());
|
|
1854
|
+
return sideloaded;
|
|
1855
|
+
}
|
|
1724
1856
|
/**
|
|
1725
1857
|
* Override to customize the id key name if it's not 'id'
|
|
1726
1858
|
* @returns The name of the unique identifier key that will be used to
|
|
@@ -1753,8 +1885,9 @@ class SPMatEntityCrudFormBase {
|
|
|
1753
1885
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: SPMatEntityCrudFormBase, decorators: [{
|
|
1754
1886
|
type: Component,
|
|
1755
1887
|
args: [{
|
|
1756
|
-
selector: '_#_sp-mat-entity-crud-form-base_#_',
|
|
1757
|
-
|
|
1888
|
+
selector: '_#_sp-mat-entity-crud-form-base_#_',
|
|
1889
|
+
template: ``,
|
|
1890
|
+
standalone: false,
|
|
1758
1891
|
}]
|
|
1759
1892
|
}] });
|
|
1760
1893
|
|