@smallpearl/ngx-helper 0.29.23
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 +230 -0
- package/core/index.d.ts +2 -0
- package/core/src/ngx-helper.d.ts +7 -0
- package/core/src/version.d.ts +1 -0
- package/entity-field/index.d.ts +2 -0
- package/entity-field/src/entity-field-spec.d.ts +69 -0
- package/entity-field/src/provider.d.ts +27 -0
- package/fesm2022/smallpearl-ngx-helper-core.mjs +23 -0
- package/fesm2022/smallpearl-ngx-helper-core.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-entity-field.mjs +112 -0
- package/fesm2022/smallpearl-ngx-helper-entity-field.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-forms.mjs +112 -0
- package/fesm2022/smallpearl-ngx-helper-forms.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs +108 -0
- package/fesm2022/smallpearl-ngx-helper-hover-dropdown.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-locale.mjs +296 -0
- package/fesm2022/smallpearl-ngx-helper-locale.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs +504 -0
- package/fesm2022/smallpearl-ngx-helper-mat-busy-wheel.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs +184 -0
- package/fesm2022/smallpearl-ngx-helper-mat-context-menu.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs +1486 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-crud.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs +800 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs +328 -0
- package/fesm2022/smallpearl-ngx-helper-mat-file-input.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs +468 -0
- package/fesm2022/smallpearl-ngx-helper-mat-form-error.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs +854 -0
- package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs +930 -0
- package/fesm2022/smallpearl-ngx-helper-mat-side-menu-layout.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs +926 -0
- package/fesm2022/smallpearl-ngx-helper-mat-tel-input.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-sideload.mjs +111 -0
- package/fesm2022/smallpearl-ngx-helper-sideload.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs +384 -0
- package/fesm2022/smallpearl-ngx-helper-stationary-with-line-items.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper.mjs +13 -0
- package/fesm2022/smallpearl-ngx-helper.mjs.map +1 -0
- package/forms/index.d.ts +1 -0
- package/forms/src/validation-error-handler.d.ts +52 -0
- package/hover-dropdown/index.d.ts +1 -0
- package/hover-dropdown/src/hover-dropdown.directive.d.ts +41 -0
- package/index.d.ts +5 -0
- package/locale/index.d.ts +5 -0
- package/locale/src/currency.pipe.d.ts +14 -0
- package/locale/src/date.pipe.d.ts +14 -0
- package/locale/src/format-currency.d.ts +1 -0
- package/locale/src/format-date.d.ts +2 -0
- package/locale/src/is-empty.d.ts +1 -0
- package/locale/src/providers.d.ts +20 -0
- package/mat-busy-wheel/index.d.ts +4 -0
- package/mat-busy-wheel/src/busy-wheel-op.d.ts +65 -0
- package/mat-busy-wheel/src/busy-wheel.component.d.ts +12 -0
- package/mat-busy-wheel/src/busy-wheel.service.d.ts +42 -0
- package/mat-busy-wheel/src/host-busy-wheel.directive.d.ts +35 -0
- package/mat-context-menu/index.d.ts +1 -0
- package/mat-context-menu/src/mat-context-menu.component.d.ts +54 -0
- package/mat-entity-crud/index.d.ts +5 -0
- package/mat-entity-crud/src/default-config.d.ts +9 -0
- package/mat-entity-crud/src/form-view-host.component.d.ts +34 -0
- package/mat-entity-crud/src/mat-entity-crud-form-base.d.ts +95 -0
- package/mat-entity-crud/src/mat-entity-crud-internal-types.d.ts +66 -0
- package/mat-entity-crud/src/mat-entity-crud-types.d.ts +141 -0
- package/mat-entity-crud/src/mat-entity-crud.component.d.ts +267 -0
- package/mat-entity-crud/src/preview-host.component.d.ts +19 -0
- package/mat-entity-crud/src/preview-pane.component.d.ts +27 -0
- package/mat-entity-crud/src/providers.d.ts +3 -0
- package/mat-entity-list/index.d.ts +3 -0
- package/mat-entity-list/src/config.d.ts +6 -0
- package/mat-entity-list/src/mat-entity-list-types.d.ts +53 -0
- package/mat-entity-list/src/mat-entity-list.component.d.ts +209 -0
- package/mat-entity-list/src/providers.d.ts +3 -0
- package/mat-file-input/README.md +63 -0
- package/mat-file-input/index.d.ts +1 -0
- package/mat-file-input/src/mat-file-input.component.d.ts +58 -0
- package/mat-form-error/README.md +306 -0
- package/mat-form-error/index.d.ts +6 -0
- package/mat-form-error/src/locales/en.d.ts +4 -0
- package/mat-form-error/src/locales/hu.d.ts +4 -0
- package/mat-form-error/src/locales/index.d.ts +3 -0
- package/mat-form-error/src/locales/pt-br.d.ts +4 -0
- package/mat-form-error/src/ngx-error-list.component.d.ts +9 -0
- package/mat-form-error/src/ngx-mat-error-control.d.ts +17 -0
- package/mat-form-error/src/ngx-mat-error-def.directive.d.ts +30 -0
- package/mat-form-error/src/ngx-mat-errors-for-date-range-picker.directive.d.ts +8 -0
- package/mat-form-error/src/ngx-mat-errors.component.d.ts +23 -0
- package/mat-form-error/src/types.d.ts +68 -0
- package/mat-form-error/src/utils/coerce-to-observable.d.ts +3 -0
- package/mat-form-error/src/utils/distinct-until-error-changed.d.ts +2 -0
- package/mat-form-error/src/utils/find-error-for-control.d.ts +9 -0
- package/mat-form-error/src/utils/get-abstract-controls.d.ts +3 -0
- package/mat-form-error/src/utils/get-control-with-error.d.ts +3 -0
- package/mat-select-entity/index.d.ts +2 -0
- package/mat-select-entity/src/mat-select-entity.component.d.ts +207 -0
- package/mat-select-entity/src/providers.d.ts +9 -0
- package/mat-side-menu-layout/index.d.ts +6 -0
- package/mat-side-menu-layout/src/layout.service.d.ts +23 -0
- package/mat-side-menu-layout/src/mat-menu-layout.component.d.ts +39 -0
- package/mat-side-menu-layout/src/mat-menu-layout.module.d.ts +18 -0
- package/mat-side-menu-layout/src/mat-menu-list-item.component.d.ts +36 -0
- package/mat-side-menu-layout/src/mat-menu-pane.component.d.ts +66 -0
- package/mat-side-menu-layout/src/nav-item.d.ts +10 -0
- package/mat-tel-input/README.md +18 -0
- package/mat-tel-input/index.d.ts +2 -0
- package/mat-tel-input/src/country-codes.d.ts +5 -0
- package/mat-tel-input/src/mat-telephone.component.d.ts +129 -0
- package/mat-tel-input/src/providers.d.ts +38 -0
- package/ngx-helper.d.ts +2 -0
- package/package.json +114 -0
- package/public-api.d.ts +1 -0
- package/sideload/index.d.ts +1 -0
- package/sideload/src/sideload.d.ts +17 -0
- package/stationary-with-line-items/index.d.ts +1 -0
- package/stationary-with-line-items/src/stationary-with-line-items.component.d.ts +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# ngx-helper
|
|
2
|
+
|
|
3
|
+
A library of UI components that covers requirements not met by standard
|
|
4
|
+
components in `@angular/material` library.
|
|
5
|
+
|
|
6
|
+
# Components
|
|
7
|
+
|
|
8
|
+
## qq-mat-file-input
|
|
9
|
+
A File Input Control that shows a thumbnail of the selected file. This can be
|
|
10
|
+
used wherever an <input matInput type='file'> is required.
|
|
11
|
+
|
|
12
|
+
## qq-mat-tel-input
|
|
13
|
+
A lightweight telephone numner input control that allows country selection by
|
|
14
|
+
typing the country name or country code.
|
|
15
|
+
|
|
16
|
+
Dependencies:
|
|
17
|
+
* google-libphonenumber - ^3.2.34
|
|
18
|
+
* ngx-mat-select-search - ^7.0.5
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## qq-mat-menu-list-item
|
|
22
|
+
A primitive component for the `qq-mat-menu-pane` component that allows building
|
|
23
|
+
a side menu based UI. This component supports hierarchical relationship with
|
|
24
|
+
itself, in which case the the parent menu item componet will display a chevron
|
|
25
|
+
to indicate child menu items.
|
|
26
|
+
|
|
27
|
+
Menu item can specified as the `item` attribute value of type `NavItem`.
|
|
28
|
+
|
|
29
|
+
### Inputs
|
|
30
|
+
|
|
31
|
+
| Name | Description |
|
|
32
|
+
|------|-------------|
|
|
33
|
+
| item | `NavItem` object representing the menu item. |
|
|
34
|
+
|
|
35
|
+
### Color customization
|
|
36
|
+
Since application's UI (where this component will be typically used) would
|
|
37
|
+
require color customization, this component uses the following CSS variables
|
|
38
|
+
for its color.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
| Variable | Description |
|
|
42
|
+
|----------|-------------|
|
|
43
|
+
| --qq-menu-item-bg-color | Menu item background color |
|
|
44
|
+
| --qq-menu-item-fg-color | Menu item foreground color |
|
|
45
|
+
| --qq-highlighted-menu-item-bg-color | Highlighted menu item background color |
|
|
46
|
+
| --qq-highlighted-menu-item-fg-color | Highlighted menu item foreground color |
|
|
47
|
+
|
|
48
|
+
## qq-mat-menu-pane
|
|
49
|
+
A parent container component that functions as the menu pane for the
|
|
50
|
+
`mat-sidenav` based user interface. The sidenav user interface (or layout),
|
|
51
|
+
consisting of a sidenav and a top toolbar, is wrapped as a component in
|
|
52
|
+
`sp-mat-menu-layout` described below.
|
|
53
|
+
|
|
54
|
+
This component takes an array of `NavItem` objects and renders it as the menu
|
|
55
|
+
in a container `div`. Typically this `div` will be hosted in a `mat-sidenav` as
|
|
56
|
+
part of an applications primary UI.
|
|
57
|
+
|
|
58
|
+
### Inputs
|
|
59
|
+
|
|
60
|
+
| Name | Description |
|
|
61
|
+
|------|-------------|
|
|
62
|
+
| brandingImage | Branding logo (32x32) that will be displayed on the top of the menu pane. |
|
|
63
|
+
| brandingText | Branding text that is displayed next to the logo on the top of the menu pane. |
|
|
64
|
+
| menuItems | Menu items which is an array of `NavItem` objects. |
|
|
65
|
+
| menuPaneFooterContent | `TemplateRef<>` content of which will be used as the footer at the bottom of the pane. |
|
|
66
|
+
| title | Title text displayed above the the menu items. |
|
|
67
|
+
| backButtonHref | If specified, the `href` for the back button displayed on the top. Will not be displayed if not set. |
|
|
68
|
+
| matSideNav | `MatSideNav` instance that will host the menu pane. |
|
|
69
|
+
|
|
70
|
+
### Example
|
|
71
|
+
|
|
72
|
+
See `mat-side-menu-layout` implementation for how this component is used.
|
|
73
|
+
|
|
74
|
+
## mat-side-menu-layout
|
|
75
|
+
A component that helps implement a side menu user interface with a top toolbar.
|
|
76
|
+
The layout is responsive and hides the side menu when run on small screens.
|
|
77
|
+
Toolbar displays the app title and on the right can accommodate buttons or any
|
|
78
|
+
other content (via content projection).
|
|
79
|
+
|
|
80
|
+
To use this component, initialize it with the branding logo & text, application
|
|
81
|
+
title and menu items (`NavItem[]`). This is the sample code from the example
|
|
82
|
+
in this repo: -
|
|
83
|
+
```
|
|
84
|
+
<sp-mat-menu-layout
|
|
85
|
+
brandingImage="assets/angular.png"
|
|
86
|
+
brandingText="SMALLPEARL"
|
|
87
|
+
appTitle="QQBOOKS"
|
|
88
|
+
[menuItems]="menuItems"
|
|
89
|
+
[menuPaneFooterContent]="versionInfoFooter"
|
|
90
|
+
[toolbarTitleContent]="toolbarTitle"
|
|
91
|
+
></sp-mat-menu-layout>
|
|
92
|
+
<ng-template #versionInfoFooter>
|
|
93
|
+
<div style="text-align: center; font-size: 0.8em;">
|
|
94
|
+
<select name="language" id="language">
|
|
95
|
+
<option value="en">English</option>
|
|
96
|
+
<option value="zh">中文</option>
|
|
97
|
+
</select>
|
|
98
|
+
<br />
|
|
99
|
+
<small>2.3.102</small>
|
|
100
|
+
</div>
|
|
101
|
+
</ng-template>
|
|
102
|
+
<ng-template #toolbarTitle>
|
|
103
|
+
<button mat-button [matMenuTriggerFor]="otherCommunitiesMenu">
|
|
104
|
+
<h4 class="community-name">Signature Park</h4>
|
|
105
|
+
<mat-icon iconPositionEnd>arrow_drop_down</mat-icon>
|
|
106
|
+
</button>
|
|
107
|
+
<mat-menu #otherCommunitiesMenu="matMenu">
|
|
108
|
+
<button mat-menu-item>Cavenagh Garden</button>
|
|
109
|
+
<button mat-menu-item>Cashew Heights</button>
|
|
110
|
+
</mat-menu>
|
|
111
|
+
</ng-template>
|
|
112
|
+
<ng-template #toolbarEndContent>
|
|
113
|
+
<button mat-icon-button (click)="onNotificationsToggle()">
|
|
114
|
+
<mat-icon>notifications</mat-icon>
|
|
115
|
+
</button>
|
|
116
|
+
<button
|
|
117
|
+
mat-icon-button
|
|
118
|
+
class="user-button"
|
|
119
|
+
[matMenuTriggerFor]="userProfileMenu"
|
|
120
|
+
>
|
|
121
|
+
<img src="assets/avatar.jpg" alt="" />
|
|
122
|
+
</button>
|
|
123
|
+
<mat-menu #userProfileMenu="matMenu">
|
|
124
|
+
<button mat-menu-item (click)="onUpdateProfile()">
|
|
125
|
+
<mat-icon>face</mat-icon>
|
|
126
|
+
<span>Profile</span>
|
|
127
|
+
</button>
|
|
128
|
+
<button mat-menu-item (click)="onChangePassword()">
|
|
129
|
+
<mat-icon>password</mat-icon>
|
|
130
|
+
<span>Change password</span>
|
|
131
|
+
</button>
|
|
132
|
+
<button mat-menu-item (click)="onSignOut()">
|
|
133
|
+
<mat-icon>logout</mat-icon>
|
|
134
|
+
<span>Sign out</span>
|
|
135
|
+
</button>
|
|
136
|
+
</mat-menu>
|
|
137
|
+
</ng-template>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Inputs
|
|
141
|
+
| Name | Type | Description |
|
|
142
|
+
|------|------|-------|
|
|
143
|
+
| showBackButton | boolean | A boolean property that controls if a Back button should be displayed at the top of the side menu. This is useful for secondary menus (note that this is NOT a submenu) from where a navigation path to the parent menu ought to be provided. |
|
|
144
|
+
| defaultBackButtonHref | string | The href for the back button is typically automatically determined. If there's no back history, the back button (if specified) will use this href. |
|
|
145
|
+
| brandingImage | string | Branding logo (32x32) that will be displayed on the top of the menu pane. |
|
|
146
|
+
| brandingText | string | Branding text that is displayed next to the logo on the top of the menu pane. |
|
|
147
|
+
| menuItems | NavItem[] | Menu items which is an array of `NavItem` objects. |
|
|
148
|
+
| appTitle | string | Application title. |
|
|
149
|
+
| menuPaneFooterContent | `TemplateRef<any>` | NgTemplate for the footer displayed below side menu. This will be passed to the `qq-mat-menu-pane`. |
|
|
150
|
+
| toolbarEndContent | `TemplateRef<any>` | NgTemplate for the content displayed at the end of the top toolbar. |
|
|
151
|
+
| infoPaneContent | `TemplateRef<any>` | NgTemplate for the content displayed in the information pane at the end of the page. |
|
|
152
|
+
| toolbarTitleContent | `TemplateRef<any>` | NgTemplate for the toolbar title. If specified, `appTitle` will be ignored. |
|
|
153
|
+
| infoPaneMinWidth | number | Minimum width of the info pane at the end of the page (right on LTR text). |
|
|
154
|
+
| infoPaneMaxWidth | number | Maximum width of the info pane at the end of the page (right on LTR text). |
|
|
155
|
+
| contentContainerClass | string | If specified, the CSS class that is applied to the content container div. This allows global styling of the container class (possibly padding, margin, color, etc) that will be applied to all the compoents corresponding to each menu item's link. |
|
|
156
|
+
| menuTitle | string | A title for the menu pane. Typically used in secondary side-menu layout pages. Defaults to an empty string. |
|
|
157
|
+
|
|
158
|
+
### CSS
|
|
159
|
+
|
|
160
|
+
| Variable | Description |
|
|
161
|
+
|----------|-------------|
|
|
162
|
+
| --qq-sidenav-bg-color | Sidenav menu pane background color |
|
|
163
|
+
| --qq-sidenav-fg-color | Sidenav menu pane foreground color |
|
|
164
|
+
| --qq-toolbar-bg-color | Toolbar background color |
|
|
165
|
+
| --qq-toolbar-fg-color | Toolbar foreground color |
|
|
166
|
+
| --qq-sidenav-border-color | Sidemenu border color |
|
|
167
|
+
| --qq-toolbar-border-color | Toolbar border color |
|
|
168
|
+
| --qq-menu-item-fg-color | Menu item foreground color |
|
|
169
|
+
| --qq-menu-item-bg-color | Menu item background color |
|
|
170
|
+
| --qq-highlighted-menu-item-fg-color | Highlighted menu item foreground color |
|
|
171
|
+
| --qq-highlighted-menu-item-bg-color | Highlighted menu item background color |
|
|
172
|
+
|
|
173
|
+
### Info pane
|
|
174
|
+
|
|
175
|
+
The component supports an information pane on the end of the pag. But it's
|
|
176
|
+
hidden by default and has to be explicitly shown. One way to do that would be
|
|
177
|
+
to query the `infoPane` member of `SPMatMenuLayoutComponent`
|
|
178
|
+
which is an instance of the `MatSideNav` component. You can toggle its
|
|
179
|
+
visibility by calling its `toggle()` method. An approach could be to show a
|
|
180
|
+
button at the end of the toolbar and then call `infoPane.toggle()` when the
|
|
181
|
+
button is selected.
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
export class AppHomeComponent implements OnInit {
|
|
185
|
+
@ViewChild(SPMatMenuLayoutComponent)
|
|
186
|
+
sideMenuLayout: SPMatMenuLayoutComponent;
|
|
187
|
+
|
|
188
|
+
ngOnInit(): void {}
|
|
189
|
+
|
|
190
|
+
...
|
|
191
|
+
onNotificationsToggle() {
|
|
192
|
+
if (this.sideMenuLayout) {
|
|
193
|
+
this.sideMenuLayout.infoPane.toggle();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
...
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## NavItem
|
|
201
|
+
|
|
202
|
+
This is the interface that is used to define the side menu items and pass it
|
|
203
|
+
as the value for the `menuItems` property. It is defined as:-
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
export interface NavItem {
|
|
207
|
+
text: string;
|
|
208
|
+
icon: string;
|
|
209
|
+
iconType?: 'mat' | 'bi' | 'fa';
|
|
210
|
+
disabled?: boolean;
|
|
211
|
+
route?: string;
|
|
212
|
+
children?: NavItem[];
|
|
213
|
+
backButton?: boolean;
|
|
214
|
+
backHref?: string;
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
Members are described in the following table:
|
|
218
|
+
|
|
219
|
+
| Member | Description |
|
|
220
|
+
|-------|----|
|
|
221
|
+
| text | The menu item text |
|
|
222
|
+
| icon | Icon displayed along with the text |
|
|
223
|
+
| iconType | One of {'mat'|'bi'|'fa'}. If not specified, defaults to 'mat' |
|
|
224
|
+
| disabled | Indicates that the menu item is disabled |
|
|
225
|
+
| route | The relative URL to navigate when the item is selected |
|
|
226
|
+
| children | If this item is a container for child menu items, set this to an array of `NavItem` objects |
|
|
227
|
+
| backButton | Used internally |
|
|
228
|
+
| backHref | Used internally |
|
|
229
|
+
|
|
230
|
+
|
package/core/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Version of the ngx-helper library */
|
|
2
|
+
import { InjectionToken } from '@angular/core';
|
|
3
|
+
export interface SPNgxHelperConfig {
|
|
4
|
+
i18nTranslate: (label: string, context?: any) => string;
|
|
5
|
+
}
|
|
6
|
+
export declare const SP_NGX_HELPER_CONFIG: InjectionToken<SPNgxHelperConfig>;
|
|
7
|
+
export declare function getNgxHelperConfig(): SPNgxHelperConfig;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const NGX_HELPER_VERSION = "0.1.0";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { SPNgxHelperConfig } from '@smallpearl/ngx-helper/core';
|
|
2
|
+
import { SPIntlDateFormat } from '@smallpearl/ngx-helper/locale';
|
|
3
|
+
import { SPEntityFieldConfig } from './provider';
|
|
4
|
+
/**
|
|
5
|
+
* This structure defines the data formatting details for a field of the
|
|
6
|
+
* entity. All entity fields need not necessarily be actual entity object's
|
|
7
|
+
* properties. Fields can also be computed fields, in which case the valueFn
|
|
8
|
+
* should be initialized with a valid function to provide the field's value.
|
|
9
|
+
*/
|
|
10
|
+
export type SPEntityFieldSpec<TEntity extends {
|
|
11
|
+
[P in IdKey]: PropertyKey;
|
|
12
|
+
}, IdKey extends string = 'id'> = {
|
|
13
|
+
name: string;
|
|
14
|
+
label?: string;
|
|
15
|
+
valueOptions?: {
|
|
16
|
+
dateTimeFormat?: SPIntlDateFormat;
|
|
17
|
+
isCurrency?: boolean;
|
|
18
|
+
currency?: string;
|
|
19
|
+
class?: string;
|
|
20
|
+
alignment?: 'start' | 'center' | 'end';
|
|
21
|
+
routerLink?: ((e: TEntity) => string[]) | [string];
|
|
22
|
+
};
|
|
23
|
+
valueFn?: (item: TEntity) => string | number | Date | boolean;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* A class that represents a SPEntityFieldSpec<>. This is typically used
|
|
27
|
+
* by the library to evaluate a SPEntityFieldSpec<> object.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SPEntityField<TEntity extends {
|
|
30
|
+
[P in IdKey]: PropertyKey;
|
|
31
|
+
}, IdKey extends string = 'id'> {
|
|
32
|
+
helperConfig: SPNgxHelperConfig;
|
|
33
|
+
fieldConfig?: SPEntityFieldConfig | undefined;
|
|
34
|
+
_fieldSpec: SPEntityFieldSpec<TEntity, IdKey>;
|
|
35
|
+
constructor(spec: SPEntityFieldSpec<TEntity, IdKey> | string, helperConfig: SPNgxHelperConfig, fieldConfig?: SPEntityFieldConfig | undefined);
|
|
36
|
+
get spec(): SPEntityFieldSpec<TEntity, IdKey>;
|
|
37
|
+
/**
|
|
38
|
+
* Returns the effective fieldValueOptions by merging the global field
|
|
39
|
+
* options (if one has been spefified) with the local field value options.
|
|
40
|
+
* @returns SPEntityFieldSpec<any>['valueOptions']
|
|
41
|
+
*/
|
|
42
|
+
get options(): {
|
|
43
|
+
dateTimeFormat?: SPIntlDateFormat;
|
|
44
|
+
isCurrency?: boolean;
|
|
45
|
+
currency?: string;
|
|
46
|
+
class?: string;
|
|
47
|
+
alignment?: "start" | "center" | "end";
|
|
48
|
+
routerLink?: [string] | ((e: TEntity) => string[]) | undefined;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* @returns the label for the field.
|
|
52
|
+
*/
|
|
53
|
+
label(): string;
|
|
54
|
+
/**
|
|
55
|
+
* Given an entity, returns the value of the field matching the
|
|
56
|
+
* SPEntityFieldSpec<> in fieldSpec.
|
|
57
|
+
* @param entity TEntity instance which will be evaluated for
|
|
58
|
+
* SPEntityFieldSpec<>.
|
|
59
|
+
* @returns
|
|
60
|
+
*/
|
|
61
|
+
value(entity: TEntity): any;
|
|
62
|
+
/**
|
|
63
|
+
* If specified, will be added to the CSS classes of the field's wrapper
|
|
64
|
+
* element.
|
|
65
|
+
*/
|
|
66
|
+
get class(): string;
|
|
67
|
+
hasRouterLink(entity: TEntity): boolean;
|
|
68
|
+
getRouterLink(entity: TEntity): string[];
|
|
69
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
import { SPEntityFieldSpec } from './entity-field-spec';
|
|
3
|
+
export type FIELD_VALUE_FN = (entity: any, fieldName: string) => string | number | Date | boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Global config for SPEntityField component.
|
|
6
|
+
*/
|
|
7
|
+
export interface SPEntityFieldConfig {
|
|
8
|
+
/**
|
|
9
|
+
* These are global field value functions.
|
|
10
|
+
*
|
|
11
|
+
* If a value function for a field is not explicitly specified, this map is
|
|
12
|
+
* looked up with the field name. If an entry exists in this table, it will
|
|
13
|
+
* be used to render the field's value.
|
|
14
|
+
*
|
|
15
|
+
* This is useful for formatting certain fields which tend to have the
|
|
16
|
+
* same name across the app. For instance fields such as 'amount', 'total'
|
|
17
|
+
* or 'balance'. Or 'date', 'timestamp', etc.
|
|
18
|
+
*/
|
|
19
|
+
fieldValueFns?: Map<string, FIELD_VALUE_FN>;
|
|
20
|
+
/**
|
|
21
|
+
* Similar to above, but allows setting the options for certain fields
|
|
22
|
+
* globally. As in the case of `fieldValueFns`, the per field specification,
|
|
23
|
+
* if one exists, takes precedence over the global setting.
|
|
24
|
+
*/
|
|
25
|
+
fieldValueOptions?: Map<string, SPEntityFieldSpec<any>['valueOptions']>;
|
|
26
|
+
}
|
|
27
|
+
export declare const SP_ENTITY_FIELD_CONFIG: InjectionToken<SPEntityFieldConfig>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { InjectionToken, inject } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
const NGX_HELPER_VERSION = '0.1.0';
|
|
4
|
+
|
|
5
|
+
/** Version of the ngx-helper library */
|
|
6
|
+
const SP_NGX_HELPER_CONFIG = new InjectionToken('SPNgxHelperConfig');
|
|
7
|
+
function getNgxHelperConfig() {
|
|
8
|
+
const defaultNgxHelperConfig = {
|
|
9
|
+
i18nTranslate: (label, context) => label
|
|
10
|
+
};
|
|
11
|
+
const helperConfig = inject(SP_NGX_HELPER_CONFIG, { optional: true });
|
|
12
|
+
return {
|
|
13
|
+
...defaultNgxHelperConfig,
|
|
14
|
+
...(helperConfig ?? {}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generated bundle index. Do not edit.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export { NGX_HELPER_VERSION, SP_NGX_HELPER_CONFIG, getNgxHelperConfig };
|
|
23
|
+
//# sourceMappingURL=smallpearl-ngx-helper-core.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smallpearl-ngx-helper-core.mjs","sources":["../../../../projects/smallpearl/ngx-helper/core/src/version.ts","../../../../projects/smallpearl/ngx-helper/core/src/ngx-helper.ts","../../../../projects/smallpearl/ngx-helper/core/smallpearl-ngx-helper-core.ts"],"sourcesContent":["export const NGX_HELPER_VERSION = '0.1.0';\n","/** Version of the ngx-helper library */\nimport { inject, InjectionToken } from '@angular/core';\n\nexport interface SPNgxHelperConfig {\n i18nTranslate: (label: string, context?: any) => string;\n}\n\nexport const SP_NGX_HELPER_CONFIG = new InjectionToken<SPNgxHelperConfig>(\n 'SPNgxHelperConfig'\n);\n\nexport function getNgxHelperConfig(): SPNgxHelperConfig {\n const defaultNgxHelperConfig: SPNgxHelperConfig = {\n i18nTranslate: (label: string, context?: any) => label\n }\n const helperConfig = inject(SP_NGX_HELPER_CONFIG, {optional: true});\n return {\n ...defaultNgxHelperConfig,\n ...(helperConfig ?? {}),\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAAO,MAAM,kBAAkB,GAAG;;ACAlC;MAOa,oBAAoB,GAAG,IAAI,cAAc,CACpD,mBAAmB;SAGL,kBAAkB,GAAA;AAChC,IAAA,MAAM,sBAAsB,GAAsB;QAChD,aAAa,EAAE,CAAC,KAAa,EAAE,OAAa,KAAK;KAClD;AACD,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,oBAAoB,EAAE,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC;IACnE,OAAO;AACL,QAAA,GAAG,sBAAsB;AACzB,QAAA,IAAI,YAAY,IAAI,EAAE,CAAC;KACxB;AACH;;ACpBA;;AAEG;;;;"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { spFormatDate, spFormatCurrency } from '@smallpearl/ngx-helper/locale';
|
|
2
|
+
import { InjectionToken } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A class that represents a SPEntityFieldSpec<>. This is typically used
|
|
6
|
+
* by the library to evaluate a SPEntityFieldSpec<> object.
|
|
7
|
+
*/
|
|
8
|
+
class SPEntityField {
|
|
9
|
+
helperConfig;
|
|
10
|
+
fieldConfig;
|
|
11
|
+
_fieldSpec;
|
|
12
|
+
constructor(spec, helperConfig, fieldConfig) {
|
|
13
|
+
this.helperConfig = helperConfig;
|
|
14
|
+
this.fieldConfig = fieldConfig;
|
|
15
|
+
if (typeof spec === 'string') {
|
|
16
|
+
this._fieldSpec = {
|
|
17
|
+
name: spec,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
this._fieldSpec = spec;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
get spec() {
|
|
25
|
+
return this._fieldSpec;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Returns the effective fieldValueOptions by merging the global field
|
|
29
|
+
* options (if one has been spefified) with the local field value options.
|
|
30
|
+
* @returns SPEntityFieldSpec<any>['valueOptions']
|
|
31
|
+
*/
|
|
32
|
+
get options() {
|
|
33
|
+
let globalFieldValueOptions = {};
|
|
34
|
+
if (this.fieldConfig && this.fieldConfig?.fieldValueOptions && this.fieldConfig.fieldValueOptions.has(this._fieldSpec.name)) {
|
|
35
|
+
globalFieldValueOptions = this.fieldConfig.fieldValueOptions.get(this._fieldSpec.name);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
...globalFieldValueOptions,
|
|
39
|
+
...(this._fieldSpec?.valueOptions ?? {})
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* @returns the label for the field.
|
|
44
|
+
*/
|
|
45
|
+
label() {
|
|
46
|
+
return this.helperConfig.i18nTranslate(this._fieldSpec.label ?? this._fieldSpec.name);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Given an entity, returns the value of the field matching the
|
|
50
|
+
* SPEntityFieldSpec<> in fieldSpec.
|
|
51
|
+
* @param entity TEntity instance which will be evaluated for
|
|
52
|
+
* SPEntityFieldSpec<>.
|
|
53
|
+
* @returns
|
|
54
|
+
*/
|
|
55
|
+
value(entity) {
|
|
56
|
+
let val = undefined;
|
|
57
|
+
if (!this._fieldSpec.valueFn) {
|
|
58
|
+
if (this.fieldConfig &&
|
|
59
|
+
this.fieldConfig?.fieldValueFns &&
|
|
60
|
+
this.fieldConfig.fieldValueFns.has(this._fieldSpec.name)) {
|
|
61
|
+
val = this.fieldConfig.fieldValueFns.get(this._fieldSpec.name)(entity, this._fieldSpec.name);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
val = entity[this._fieldSpec.name];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
val = this._fieldSpec.valueFn(entity);
|
|
69
|
+
}
|
|
70
|
+
const valueOptions = this.options;
|
|
71
|
+
if (val instanceof Date) {
|
|
72
|
+
val = spFormatDate(val);
|
|
73
|
+
}
|
|
74
|
+
else if (typeof val === 'number' &&
|
|
75
|
+
valueOptions?.isCurrency) {
|
|
76
|
+
val = spFormatCurrency(val, this._fieldSpec?.valueOptions?.currency);
|
|
77
|
+
}
|
|
78
|
+
else if (typeof val === 'boolean') {
|
|
79
|
+
val = val ? '✔' : '✖';
|
|
80
|
+
}
|
|
81
|
+
return val;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* If specified, will be added to the CSS classes of the field's wrapper
|
|
85
|
+
* element.
|
|
86
|
+
*/
|
|
87
|
+
get class() {
|
|
88
|
+
return this._fieldSpec?.valueOptions?.class ?? '';
|
|
89
|
+
}
|
|
90
|
+
hasRouterLink(entity) {
|
|
91
|
+
return !!this._fieldSpec?.valueOptions?.routerLink;
|
|
92
|
+
}
|
|
93
|
+
getRouterLink(entity) {
|
|
94
|
+
const rl = this._fieldSpec?.valueOptions?.routerLink;
|
|
95
|
+
if (rl) {
|
|
96
|
+
if (typeof rl == 'function') {
|
|
97
|
+
return rl(entity);
|
|
98
|
+
}
|
|
99
|
+
return rl;
|
|
100
|
+
}
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const SP_ENTITY_FIELD_CONFIG = new InjectionToken('SPEntityFieldConfig');
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Generated bundle index. Do not edit.
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
export { SPEntityField, SP_ENTITY_FIELD_CONFIG };
|
|
112
|
+
//# sourceMappingURL=smallpearl-ngx-helper-entity-field.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smallpearl-ngx-helper-entity-field.mjs","sources":["../../../../projects/smallpearl/ngx-helper/entity-field/src/entity-field-spec.ts","../../../../projects/smallpearl/ngx-helper/entity-field/src/provider.ts","../../../../projects/smallpearl/ngx-helper/entity-field/smallpearl-ngx-helper-entity-field.ts"],"sourcesContent":["import { SPNgxHelperConfig } from '@smallpearl/ngx-helper/core';\nimport {\n spFormatCurrency,\n spFormatDate,\n SPIntlDateFormat,\n} from '@smallpearl/ngx-helper/locale';\nimport { SPEntityFieldConfig } from './provider';\n\n/**\n * This structure defines the data formatting details for a field of the\n * entity. All entity fields need not necessarily be actual entity object's\n * properties. Fields can also be computed fields, in which case the valueFn\n * should be initialized with a valid function to provide the field's value.\n */\nexport type SPEntityFieldSpec<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> = {\n // Column name. If valueFn is not specified, this will be used as the\n // key name to retrieve the value for the column from TEntity.\n name: string;\n // If omitted, 'name' will be used as field label.\n label?: string;\n // Column value specific formatting options. Currently, only used for\n // Date types.\n valueOptions?: {\n // Specify the same format string argument that is passed to DatePipe.\n dateTimeFormat?: SPIntlDateFormat;\n // If boolean, number field will be formatted using spFormatCurrency()\n // using the current currency or 'currency' value below.\n isCurrency?: boolean;\n // Currency code, if different from default locale.\n currency?: string;\n // CSS class name; if provided will be applied to field value's wrapper\n // element. This will be <td> & <th>.\n class?: string;\n // Alignment options. Field's value will be aligned based on this.\n alignment?: 'start'|'center'|'end';\n // A fixed string or a function that returns an array of strings\n // to be used as the routerlink for the column value.\n routerLink?: ((e: TEntity) => string[])|[string];\n };\n // If the column value cannot be derived by simple TEntity[name] lookup,\n // use this function to return a custom computed or formatted value.\n valueFn?: (item: TEntity) => string | number | Date | boolean;\n};\n\n/**\n * A class that represents a SPEntityFieldSpec<>. This is typically used\n * by the library to evaluate a SPEntityFieldSpec<> object.\n */\nexport class SPEntityField<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'> {\n public _fieldSpec!: SPEntityFieldSpec<TEntity, IdKey>;\n\n constructor(\n spec: SPEntityFieldSpec<TEntity, IdKey> | string,\n public helperConfig: SPNgxHelperConfig,\n public fieldConfig?: SPEntityFieldConfig\n ) {\n if (typeof spec === 'string') {\n this._fieldSpec = {\n name: spec,\n };\n } else {\n this._fieldSpec = spec;\n }\n }\n\n get spec() {\n return this._fieldSpec;\n }\n\n /**\n * Returns the effective fieldValueOptions by merging the global field\n * options (if one has been spefified) with the local field value options.\n * @returns SPEntityFieldSpec<any>['valueOptions']\n */\n get options() {\n let globalFieldValueOptions: SPEntityFieldSpec<any>['valueOptions'] = {};\n if (this.fieldConfig && this.fieldConfig?.fieldValueOptions && this.fieldConfig.fieldValueOptions.has(this._fieldSpec.name)) {\n globalFieldValueOptions = this.fieldConfig.fieldValueOptions.get(this._fieldSpec.name);\n }\n return {\n ...globalFieldValueOptions,\n ...(this._fieldSpec?.valueOptions ?? {})\n };\n }\n /**\n * @returns the label for the field.\n */\n label() {\n return this.helperConfig.i18nTranslate(\n this._fieldSpec.label ?? this._fieldSpec.name\n );\n }\n\n /**\n * Given an entity, returns the value of the field matching the\n * SPEntityFieldSpec<> in fieldSpec.\n * @param entity TEntity instance which will be evaluated for\n * SPEntityFieldSpec<>.\n * @returns\n */\n value(entity: TEntity) {\n let val = undefined;\n if (!this._fieldSpec.valueFn) {\n if (\n this.fieldConfig &&\n this.fieldConfig?.fieldValueFns &&\n this.fieldConfig.fieldValueFns.has(this._fieldSpec.name)\n ) {\n val = this.fieldConfig.fieldValueFns.get(this._fieldSpec.name)!(entity, this._fieldSpec.name);\n } else {\n val = (entity as any)[this._fieldSpec.name];\n }\n } else {\n val = this._fieldSpec.valueFn(entity);\n }\n const valueOptions = this.options;\n if (val instanceof Date) {\n val = spFormatDate(val);\n } else if (\n typeof val === 'number' &&\n valueOptions?.isCurrency\n ) {\n val = spFormatCurrency(val, this._fieldSpec?.valueOptions?.currency);\n } else if (typeof val === 'boolean') {\n val = val ? '✔' : '✖';\n }\n return val;\n }\n\n /**\n * If specified, will be added to the CSS classes of the field's wrapper\n * element.\n */\n get class() {\n return this._fieldSpec?.valueOptions?.class ?? '';\n }\n\n hasRouterLink(entity: TEntity) {\n return !!this._fieldSpec?.valueOptions?.routerLink;\n }\n\n getRouterLink(entity: TEntity) {\n const rl = this._fieldSpec?.valueOptions?.routerLink;\n if (rl) {\n if (typeof rl == 'function') {\n return rl(entity);\n }\n return rl\n }\n return [];\n }\n}\n","import { InjectionToken } from '@angular/core';\nimport { SPEntityFieldSpec } from './entity-field-spec';\n\n\nexport type FIELD_VALUE_FN = (entity: any, fieldName: string) => string|number|Date|boolean;\n\n/**\n * Global config for SPEntityField component.\n */\nexport interface SPEntityFieldConfig {\n /**\n * These are global field value functions.\n *\n * If a value function for a field is not explicitly specified, this map is\n * looked up with the field name. If an entry exists in this table, it will\n * be used to render the field's value.\n *\n * This is useful for formatting certain fields which tend to have the\n * same name across the app. For instance fields such as 'amount', 'total'\n * or 'balance'. Or 'date', 'timestamp', etc.\n */\n fieldValueFns?: Map<string, FIELD_VALUE_FN>;\n /**\n * Similar to above, but allows setting the options for certain fields\n * globally. As in the case of `fieldValueFns`, the per field specification,\n * if one exists, takes precedence over the global setting.\n */\n fieldValueOptions?: Map<string, SPEntityFieldSpec<any>['valueOptions']>;\n}\n\nexport const SP_ENTITY_FIELD_CONFIG = new InjectionToken<SPEntityFieldConfig>(\n 'SPEntityFieldConfig'\n);\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { of, throwError, catchError } from 'rxjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handle's form validation errors sent from the server by setting the returned
|
|
5
|
+
* error code in the respective control. Errors not associated with any control
|
|
6
|
+
* in the form are attached to the form itself.
|
|
7
|
+
*
|
|
8
|
+
* These errors can then be rendered using error-tailor. All that needs to be
|
|
9
|
+
* done is to import errorTailorImports in the respective page's module and set
|
|
10
|
+
* the 'errorTailor' directive on the <form..> element.
|
|
11
|
+
*
|
|
12
|
+
* @param form FormGroup instance
|
|
13
|
+
* @param error error object
|
|
14
|
+
*/
|
|
15
|
+
function handleValidationErrors(form, error, cdr) {
|
|
16
|
+
if (error.status == 400) {
|
|
17
|
+
/**
|
|
18
|
+
* A helper function that converts the server error codes to an error
|
|
19
|
+
* object that can be set on the form control. If the error code is a
|
|
20
|
+
* string with embedded spaces, it is treated as an actual error message
|
|
21
|
+
* and is set as the 'serverMessage' error code. Otherwise, the error code
|
|
22
|
+
* is returned as the object { errorCode: true }.
|
|
23
|
+
* @param errorCode
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
const serverErrorsToErrorObject = (errorCode) => {
|
|
27
|
+
if (!Array.isArray(errorCode)) {
|
|
28
|
+
errorCode = [errorCode];
|
|
29
|
+
}
|
|
30
|
+
const errorsObj = {};
|
|
31
|
+
errorCode.forEach((code) => {
|
|
32
|
+
if (code.includes(' ')) {
|
|
33
|
+
// errorCode is an actual error message that we forgot to represent
|
|
34
|
+
// as a camelcase string. So represent the error as the error code
|
|
35
|
+
// 'serverMessage', which will be treated differently by our ErrorTailor
|
|
36
|
+
// error's config provider. (see ionic-error-tailor.module.ts)
|
|
37
|
+
errorsObj['serverMessage'] = { message: code };
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// Real error code
|
|
41
|
+
errorsObj[code] = true;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return errorsObj;
|
|
45
|
+
};
|
|
46
|
+
// server form validation errors
|
|
47
|
+
let pendingDetechChanges = false;
|
|
48
|
+
for (const controlName in error.error) {
|
|
49
|
+
const errorsObj = serverErrorsToErrorObject(error.error[controlName]);
|
|
50
|
+
if (form.contains(controlName)) {
|
|
51
|
+
const control = form.controls[controlName];
|
|
52
|
+
control.setErrors(errorsObj);
|
|
53
|
+
pendingDetechChanges = true;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
form.setErrors(errorsObj);
|
|
57
|
+
pendingDetechChanges = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (pendingDetechChanges && cdr) {
|
|
61
|
+
cdr.detectChanges();
|
|
62
|
+
}
|
|
63
|
+
return of(null);
|
|
64
|
+
}
|
|
65
|
+
return throwError(() => error);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns an rxjs operator that would track an http request's error
|
|
69
|
+
* state and if the return code is 400, would enumerate the error codes
|
|
70
|
+
* set in the response body and set the error state of corresponding
|
|
71
|
+
* form controls.
|
|
72
|
+
*
|
|
73
|
+
* Use it like below:
|
|
74
|
+
*
|
|
75
|
+
* this.http.get<User>('https://google.com/..').pipe(
|
|
76
|
+
* setServerErrorsAsFormErrors(form),
|
|
77
|
+
* tap(user => {
|
|
78
|
+
* if (user) { // if user = null, it means there was a server validation
|
|
79
|
+
* // error.
|
|
80
|
+
* this.user = user;
|
|
81
|
+
* }
|
|
82
|
+
* })
|
|
83
|
+
* ).subscribe();
|
|
84
|
+
*
|
|
85
|
+
* Note that setServerErrorsAsFormErrors() is the last operator in
|
|
86
|
+
* the operators list. This is important because if a server validation
|
|
87
|
+
* error is encountered, setServerErrorsAsFormErrors(), would place
|
|
88
|
+
* the error on the respective form control and in the end would
|
|
89
|
+
* return Observable<null>. Any subsequent opeators that are added
|
|
90
|
+
* to the list after this should check for this null value in its
|
|
91
|
+
* handler.
|
|
92
|
+
*
|
|
93
|
+
* @param form The FormGroup instance where the controls corresponding
|
|
94
|
+
* to the errors are looked up and its control.error is set to the
|
|
95
|
+
* returned error code.
|
|
96
|
+
* @param cdr ChangeDetectorRef instance. If provided, it would be
|
|
97
|
+
* used to detect changes after the error codes are set on the form
|
|
98
|
+
* controls.
|
|
99
|
+
* @returns An rxjs op that can be added to the pipe() arg list.
|
|
100
|
+
*/
|
|
101
|
+
function setServerErrorsAsFormErrors(form, cdr) {
|
|
102
|
+
return function (source) {
|
|
103
|
+
return source.pipe(catchError((error) => handleValidationErrors(form, error, cdr)));
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Generated bundle index. Do not edit.
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
export { handleValidationErrors, setServerErrorsAsFormErrors };
|
|
112
|
+
//# sourceMappingURL=smallpearl-ngx-helper-forms.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smallpearl-ngx-helper-forms.mjs","sources":["../../../../projects/smallpearl/ngx-helper/forms/src/validation-error-handler.ts","../../../../projects/smallpearl/ngx-helper/forms/smallpearl-ngx-helper-forms.ts"],"sourcesContent":["import { HttpErrorResponse } from '@angular/common/http';\nimport { ChangeDetectorRef } from '@angular/core';\nimport { UntypedFormGroup } from '@angular/forms';\nimport { catchError, Observable, of, throwError } from 'rxjs';\n\n/**\n * Handle's form validation errors sent from the server by setting the returned\n * error code in the respective control. Errors not associated with any control\n * in the form are attached to the form itself.\n *\n * These errors can then be rendered using error-tailor. All that needs to be\n * done is to import errorTailorImports in the respective page's module and set\n * the 'errorTailor' directive on the <form..> element.\n *\n * @param form FormGroup instance\n * @param error error object\n */\nexport function handleValidationErrors(\n form: UntypedFormGroup,\n error: HttpErrorResponse,\n cdr?: ChangeDetectorRef\n): Observable<any> {\n if (error.status == 400) {\n /**\n * A helper function that converts the server error codes to an error\n * object that can be set on the form control. If the error code is a\n * string with embedded spaces, it is treated as an actual error message\n * and is set as the 'serverMessage' error code. Otherwise, the error code\n * is returned as the object { errorCode: true }.\n * @param errorCode\n * @returns\n */\n const serverErrorsToErrorObject = (\n errorCode: string | string[]\n ): unknown => {\n if (!Array.isArray(errorCode)) {\n errorCode = [errorCode];\n }\n const errorsObj = {};\n errorCode.forEach((code) => {\n if (code.includes(' ')) {\n // errorCode is an actual error message that we forgot to represent\n // as a camelcase string. So represent the error as the error code\n // 'serverMessage', which will be treated differently by our ErrorTailor\n // error's config provider. (see ionic-error-tailor.module.ts)\n (errorsObj as any)['serverMessage'] = { message: code };\n } else {\n // Real error code\n (errorsObj as any)[code] = true;\n }\n });\n return errorsObj;\n };\n\n // server form validation errors\n let pendingDetechChanges = false;\n for (const controlName in error.error) {\n const errorsObj = serverErrorsToErrorObject(error.error[controlName]);\n if (form.contains(controlName)) {\n const control = form.controls[controlName];\n control.setErrors(errorsObj as any);\n pendingDetechChanges = true;\n } else {\n form.setErrors(errorsObj as any);\n pendingDetechChanges = true;\n }\n }\n if (pendingDetechChanges && cdr) {\n cdr.detectChanges();\n }\n return of(null);\n }\n return throwError(() => error);\n}\n\n/**\n * Returns an rxjs operator that would track an http request's error\n * state and if the return code is 400, would enumerate the error codes\n * set in the response body and set the error state of corresponding\n * form controls.\n *\n * Use it like below:\n *\n * this.http.get<User>('https://google.com/..').pipe(\n * setServerErrorsAsFormErrors(form),\n * tap(user => {\n * if (user) { // if user = null, it means there was a server validation\n * // error.\n * this.user = user;\n * }\n * })\n * ).subscribe();\n *\n * Note that setServerErrorsAsFormErrors() is the last operator in\n * the operators list. This is important because if a server validation\n * error is encountered, setServerErrorsAsFormErrors(), would place\n * the error on the respective form control and in the end would\n * return Observable<null>. Any subsequent opeators that are added\n * to the list after this should check for this null value in its\n * handler.\n *\n * @param form The FormGroup instance where the controls corresponding\n * to the errors are looked up and its control.error is set to the\n * returned error code.\n * @param cdr ChangeDetectorRef instance. If provided, it would be\n * used to detect changes after the error codes are set on the form\n * controls.\n * @returns An rxjs op that can be added to the pipe() arg list.\n */\nexport function setServerErrorsAsFormErrors(\n form: UntypedFormGroup,\n cdr?: ChangeDetectorRef\n) {\n return function <T>(source: Observable<T>): Observable<T> {\n return source.pipe(\n catchError((error) => handleValidationErrors(form, error, cdr))\n );\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAKA;;;;;;;;;;;AAWG;SACa,sBAAsB,CACpC,IAAsB,EACtB,KAAwB,EACxB,GAAuB,EAAA;AAEvB,IAAA,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,EAAE;AACvB;;;;;;;;AAQG;AACH,QAAA,MAAM,yBAAyB,GAAG,CAChC,SAA4B,KACjB;YACX,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;AAC7B,gBAAA,SAAS,GAAG,CAAC,SAAS,CAAC;;YAEzB,MAAM,SAAS,GAAG,EAAE;AACpB,YAAA,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;AACzB,gBAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;;;;;oBAKrB,SAAiB,CAAC,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;;qBAClD;;AAEJ,oBAAA,SAAiB,CAAC,IAAI,CAAC,GAAG,IAAI;;AAEnC,aAAC,CAAC;AACF,YAAA,OAAO,SAAS;AAClB,SAAC;;QAGD,IAAI,oBAAoB,GAAG,KAAK;AAChC,QAAA,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,KAAK,EAAE;YACrC,MAAM,SAAS,GAAG,yBAAyB,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACrE,YAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;gBAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;AAC1C,gBAAA,OAAO,CAAC,SAAS,CAAC,SAAgB,CAAC;gBACnC,oBAAoB,GAAG,IAAI;;iBACtB;AACL,gBAAA,IAAI,CAAC,SAAS,CAAC,SAAgB,CAAC;gBAChC,oBAAoB,GAAG,IAAI;;;AAG/B,QAAA,IAAI,oBAAoB,IAAI,GAAG,EAAE;YAC/B,GAAG,CAAC,aAAa,EAAE;;AAErB,QAAA,OAAO,EAAE,CAAC,IAAI,CAAC;;AAEjB,IAAA,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC;AAChC;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;AACa,SAAA,2BAA2B,CACzC,IAAsB,EACtB,GAAuB,EAAA;AAEvB,IAAA,OAAO,UAAa,MAAqB,EAAA;QACvC,OAAO,MAAM,CAAC,IAAI,CAChB,UAAU,CAAC,CAAC,KAAK,KAAK,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAChE;AACH,KAAC;AACH;;ACtHA;;AAEG;;;;"}
|