ezfw-core 1.0.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/components/EzBaseComponent.ts +648 -0
- package/components/EzComponent.ts +89 -0
- package/components/EzInput.module.scss +183 -0
- package/components/EzInput.ts +104 -0
- package/components/EzLabel.ts +22 -0
- package/components/EzOutlet.ts +181 -0
- package/components/HtmlWrapper.ts +305 -0
- package/components/avatar/EzAvatar.module.scss +200 -0
- package/components/avatar/EzAvatar.ts +130 -0
- package/components/badge/EzBadge.module.scss +202 -0
- package/components/badge/EzBadge.ts +77 -0
- package/components/button/EzButton.module.scss +402 -0
- package/components/button/EzButton.ts +175 -0
- package/components/button/EzButtonGroup.ts +48 -0
- package/components/card/EzCard.module.scss +71 -0
- package/components/card/EzCard.ts +120 -0
- package/components/chart/EzBarChart.ts +47 -0
- package/components/chart/EzChart.module.scss +14 -0
- package/components/chart/EzChart.ts +279 -0
- package/components/chart/EzDoughnutChart.ts +47 -0
- package/components/chart/EzLineChart.ts +53 -0
- package/components/checkbox/EzCheckbox.module.scss +145 -0
- package/components/checkbox/EzCheckbox.ts +115 -0
- package/components/dataview/EzDataView.module.scss +115 -0
- package/components/dataview/EzDataView.ts +355 -0
- package/components/dataview/modes/EzDataViewCards.ts +322 -0
- package/components/dataview/modes/EzDataViewGrid.ts +76 -0
- package/components/datepicker/EzDatePicker.module.scss +348 -0
- package/components/datepicker/EzDatePicker.ts +519 -0
- package/components/dialog/EzDialog.module.scss +180 -0
- package/components/dropdown/EzDropdown.module.scss +107 -0
- package/components/dropdown/EzDropdown.ts +235 -0
- package/components/feed/EzActivityFeed.module.scss +90 -0
- package/components/feed/EzActivityFeed.ts +78 -0
- package/components/form/EzForm.ts +364 -0
- package/components/form/EzValidators.test.js +421 -0
- package/components/form/EzValidators.ts +202 -0
- package/components/grid/EzGrid.scss +88 -0
- package/components/grid/EzGrid.ts +1085 -0
- package/components/grid/EzGridContainer.ts +104 -0
- package/components/grid/body/EzGridBody.scss +283 -0
- package/components/grid/body/EzGridBody.ts +549 -0
- package/components/grid/body/EzGridCell.ts +211 -0
- package/components/grid/body/EzGridRow.ts +196 -0
- package/components/grid/filter/EzGridFilters.scss +78 -0
- package/components/grid/filter/EzGridFilters.ts +285 -0
- package/components/grid/footer/EzGridFooter.scss +136 -0
- package/components/grid/footer/EzGridFooter.ts +448 -0
- package/components/grid/header/EzGridHeader.scss +199 -0
- package/components/grid/header/EzGridHeader.ts +430 -0
- package/components/grid/query/EzGridQuery.ts +81 -0
- package/components/grid/state/EzGridColumns.ts +155 -0
- package/components/grid/state/EzGridController.ts +470 -0
- package/components/grid/state/EzGridLifecycle.ts +136 -0
- package/components/grid/state/EzGridNormalizers.test.js +273 -0
- package/components/grid/state/EzGridNormalizers.ts +162 -0
- package/components/grid/state/EzGridParts.ts +233 -0
- package/components/grid/state/EzGridPersistence.ts +140 -0
- package/components/grid/state/EzGridRemote.test.js +573 -0
- package/components/grid/state/EzGridRemote.ts +335 -0
- package/components/grid/state/EzGridSelection.ts +231 -0
- package/components/grid/state/EzGridSort.ts +286 -0
- package/components/grid/title/EzGridActionBar.ts +98 -0
- package/components/grid/title/EzGridTitle.ts +114 -0
- package/components/grid/title/EzGridTitleBar.scss +65 -0
- package/components/grid/title/EzGridTitleBar.ts +87 -0
- package/components/grid/types.ts +607 -0
- package/components/panel/EzPanel.module.scss +133 -0
- package/components/panel/EzPanel.ts +147 -0
- package/components/radio/EzRadio.module.scss +190 -0
- package/components/radio/EzRadio.ts +149 -0
- package/components/select/EzSelect.module.scss +153 -0
- package/components/select/EzSelect.ts +238 -0
- package/components/skeleton/EzSkeleton.module.scss +95 -0
- package/components/skeleton/EzSkeleton.ts +70 -0
- package/components/store/EzStore.ts +344 -0
- package/components/switch/EzSwitch.module.scss +164 -0
- package/components/switch/EzSwitch.ts +117 -0
- package/components/tabs/EzTabPanel.module.scss +181 -0
- package/components/tabs/EzTabPanel.ts +402 -0
- package/components/textarea/EzTextarea.module.scss +131 -0
- package/components/textarea/EzTextarea.ts +161 -0
- package/components/timepicker/EzTimePicker.module.scss +282 -0
- package/components/timepicker/EzTimePicker.ts +540 -0
- package/components/toast/EzToast.module.scss +291 -0
- package/components/tooltip/EzTooltip.module.scss +124 -0
- package/components/tooltip/EzTooltip.ts +153 -0
- package/core/EzComponentTypes.ts +693 -0
- package/core/EzError.ts +63 -0
- package/core/EzModel.ts +268 -0
- package/core/EzTypes.ts +328 -0
- package/core/eventBus.ts +284 -0
- package/core/ez.ts +617 -0
- package/core/loader.ts +725 -0
- package/core/renderer.ts +1010 -0
- package/core/router.ts +490 -0
- package/core/services.ts +124 -0
- package/core/state.ts +142 -0
- package/core/utils.ts +81 -0
- package/package.json +51 -0
- package/services/RouteUI.js +17 -0
- package/services/crypto.js +64 -0
- package/services/dialog.js +222 -0
- package/services/fetchApi.js +63 -0
- package/services/firebase.js +30 -0
- package/services/toast.js +214 -0
- package/template/doc/EzDocs.js +15 -0
- package/template/doc/EzDocs.module.scss +627 -0
- package/template/doc/EzDocsController.js +164 -0
- package/template/doc/data/activityfeed/EzActivityFeedDoc.js +42 -0
- package/template/doc/data/avatar/EzAvatarDoc.js +71 -0
- package/template/doc/data/badge/EzBadgeDoc.js +92 -0
- package/template/doc/data/button/EzButtonDoc.js +77 -0
- package/template/doc/data/buttongroup/EzButtonGroupDoc.js +102 -0
- package/template/doc/data/card/EzCardDoc.js +39 -0
- package/template/doc/data/chart/EzChartDoc.js +60 -0
- package/template/doc/data/checkbox/EzCheckboxDoc.js +67 -0
- package/template/doc/data/component/EzComponentDoc.js +34 -0
- package/template/doc/data/cssmodules/CSSModulesDoc.js +70 -0
- package/template/doc/data/datepicker/EzDatePickerDoc.js +126 -0
- package/template/doc/data/dialog/EzDialogDoc.js +217 -0
- package/template/doc/data/dropdown/EzDropdownDoc.js +178 -0
- package/template/doc/data/form/EzFormDoc.js +90 -0
- package/template/doc/data/grid/EzGridDoc.js +99 -0
- package/template/doc/data/input/EzInputDoc.js +92 -0
- package/template/doc/data/label/EzLabelDoc.js +40 -0
- package/template/doc/data/model/EzModelDoc.js +53 -0
- package/template/doc/data/outlet/EzOutletDoc.js +63 -0
- package/template/doc/data/panel/EzPanelDoc.js +214 -0
- package/template/doc/data/radio/EzRadioDoc.js +174 -0
- package/template/doc/data/router/EzRouterDoc.js +75 -0
- package/template/doc/data/select/EzSelectDoc.js +37 -0
- package/template/doc/data/skeleton/EzSkeletonDoc.js +149 -0
- package/template/doc/data/switch/EzSwitchDoc.js +82 -0
- package/template/doc/data/tabpanel/EzTabPanelDoc.js +44 -0
- package/template/doc/data/textarea/EzTextareaDoc.js +131 -0
- package/template/doc/data/timepicker/EzTimePickerDoc.js +107 -0
- package/template/doc/data/tooltip/EzTooltipDoc.js +193 -0
- package/template/doc/data/validators/EzValidatorsDoc.js +37 -0
- package/template/doc/sidebar/EzDocsSidebar.js +32 -0
- package/template/doc/sidebar/category/EzDocsCategory.js +33 -0
- package/template/doc/sidebar/item/EzDocsComponentItem.js +24 -0
- package/template/doc/viewer/EzDocsViewer.js +18 -0
- package/template/doc/viewer/codepanel/EzDocsCodePanel.js +51 -0
- package/template/doc/viewer/content/EzDocsContent.js +315 -0
- package/template/doc/viewer/header/EzDocsViewerHeader.js +46 -0
- package/template/doc/viewer/showcase/EzDocsShowcase.js +59 -0
- package/template/doc/viewer/showcase/EzDocsShowcaseSection.js +25 -0
- package/template/doc/viewer/showcase/EzDocsVariantItem.js +29 -0
- package/template/doc/welcome/EzDocsWelcome.js +48 -0
- package/themes/ez-theme.scss +179 -0
- package/themes/nature-fresh.scss +169 -0
- package/types/global.d.ts +21 -0
- package/utils/cssModules.js +81 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { EzBaseComponent, EzBaseComponentConfig } from "../EzBaseComponent.js";
|
|
2
|
+
import { validateField, EzValidators } from "./EzValidators.js";
|
|
3
|
+
|
|
4
|
+
declare const ez: {
|
|
5
|
+
_createElement(config: unknown, controller?: string | null, parent?: unknown): Promise<HTMLElement>;
|
|
6
|
+
getControllerSync(name: string): EzController | null;
|
|
7
|
+
getDeepValue(obj: unknown, path: string[]): unknown;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
interface EzController {
|
|
11
|
+
state: Record<string, unknown>;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface FormItemConfig {
|
|
16
|
+
name?: string;
|
|
17
|
+
eztype?: string;
|
|
18
|
+
validate?: unknown;
|
|
19
|
+
required?: boolean | ((data: FormData) => boolean);
|
|
20
|
+
requiredMessage?: string;
|
|
21
|
+
items?: FormItemConfig[];
|
|
22
|
+
flex?: number;
|
|
23
|
+
formData?: string;
|
|
24
|
+
css?: string | unknown;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface DefaultsConfig {
|
|
29
|
+
eztype?: string;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type FormData = Record<string, unknown>;
|
|
34
|
+
|
|
35
|
+
type OnSubmitFunction = (
|
|
36
|
+
dirtyData: FormData,
|
|
37
|
+
formData: FormData,
|
|
38
|
+
form: EzForm
|
|
39
|
+
) => void;
|
|
40
|
+
|
|
41
|
+
export interface EzFormConfig extends EzBaseComponentConfig {
|
|
42
|
+
formData?: string;
|
|
43
|
+
gap?: string;
|
|
44
|
+
layout?: number[];
|
|
45
|
+
defaults?: DefaultsConfig;
|
|
46
|
+
onSubmit?: string | OnSubmitFunction;
|
|
47
|
+
items?: FormItemConfig[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface ResolvedFormData {
|
|
51
|
+
controller: EzController;
|
|
52
|
+
props: string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class EzForm extends EzBaseComponent {
|
|
56
|
+
declare config: EzFormConfig;
|
|
57
|
+
declare el: HTMLFormElement;
|
|
58
|
+
|
|
59
|
+
private _initialFormData: FormData | null = null;
|
|
60
|
+
private _submitted: boolean = false;
|
|
61
|
+
private _errors: Record<string, string> = {};
|
|
62
|
+
private _initialFormDataCaptured: boolean = false;
|
|
63
|
+
|
|
64
|
+
constructor(config: EzFormConfig = {}) {
|
|
65
|
+
super(config);
|
|
66
|
+
this.config = config;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async render(): Promise<HTMLFormElement> {
|
|
70
|
+
const el = document.createElement('form');
|
|
71
|
+
el.className = (this.config.cls as string) || '';
|
|
72
|
+
el.style.display = 'flex';
|
|
73
|
+
el.style.flexDirection = 'column';
|
|
74
|
+
el.style.gap = this.config.gap ?? 'var(--ez-spacing-md, 12px)';
|
|
75
|
+
|
|
76
|
+
this.applyStyles(el);
|
|
77
|
+
|
|
78
|
+
el.addEventListener('submit', (e: Event) => {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
this._submitted = true;
|
|
81
|
+
|
|
82
|
+
if (!this.validate()) {
|
|
83
|
+
this._applyErrors();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
this._clearErrors();
|
|
88
|
+
this._handleSubmit();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
el.addEventListener('input', () => {
|
|
92
|
+
if (!this._submitted) return;
|
|
93
|
+
|
|
94
|
+
this.validate();
|
|
95
|
+
this._applyErrors();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const controllerName = this.config.controller;
|
|
99
|
+
|
|
100
|
+
if (!this._initialFormDataCaptured) {
|
|
101
|
+
this._captureInitialFormData();
|
|
102
|
+
this._initialFormDataCaptured = true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (Array.isArray(this.config.items)) {
|
|
106
|
+
const items = this.config.items;
|
|
107
|
+
const layout = this.config.layout;
|
|
108
|
+
|
|
109
|
+
if (Array.isArray(layout)) {
|
|
110
|
+
const expectedCount = layout.reduce((sum, n) => sum + n, 0);
|
|
111
|
+
if (items.length !== expectedCount) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`EzForm layout mismatch: layout expects ${expectedCount} items ` +
|
|
114
|
+
`(${layout.join(' + ')} = ${expectedCount}), but got ${items.length} items`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let itemIndex = 0;
|
|
119
|
+
for (const rowCount of layout) {
|
|
120
|
+
const row = document.createElement('div');
|
|
121
|
+
row.style.display = 'flex';
|
|
122
|
+
row.style.gap = this.config.gap ?? 'var(--ez-spacing-md, 12px)';
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i < rowCount; i++) {
|
|
125
|
+
const itemCfg = items[itemIndex++];
|
|
126
|
+
const finalCfg = this._prepareItemConfig(itemCfg);
|
|
127
|
+
|
|
128
|
+
if (finalCfg.flex === undefined && rowCount > 1) {
|
|
129
|
+
finalCfg.flex = 1;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const child = await ez._createElement(finalCfg, controllerName, this);
|
|
133
|
+
row.appendChild(child);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
el.appendChild(row);
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
for (const itemCfg of items) {
|
|
140
|
+
const finalCfg = this._prepareItemConfig(itemCfg);
|
|
141
|
+
const child = await ez._createElement(finalCfg, controllerName, this);
|
|
142
|
+
el.appendChild(child);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.el = el;
|
|
148
|
+
return el;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private _prepareItemConfig(itemCfg: FormItemConfig): FormItemConfig {
|
|
152
|
+
const finalCfg: FormItemConfig = {
|
|
153
|
+
...itemCfg,
|
|
154
|
+
formData: this.config.formData,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (this.config.css && !finalCfg.css) {
|
|
158
|
+
finalCfg.css = this.config.css;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!finalCfg.eztype) {
|
|
162
|
+
finalCfg.eztype = this.config.defaults?.eztype || 'EzInput';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return finalCfg;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
isDirty(): boolean {
|
|
169
|
+
if (!this._initialFormData) return false;
|
|
170
|
+
|
|
171
|
+
const current = this.getFormData();
|
|
172
|
+
if (!current) return false;
|
|
173
|
+
|
|
174
|
+
return !this._shallowEqual(current, this._initialFormData);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private _shallowEqual(a: FormData | null, b: FormData | null): boolean {
|
|
178
|
+
const aKeys = Object.keys(a || {});
|
|
179
|
+
const bKeys = Object.keys(b || {});
|
|
180
|
+
|
|
181
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
182
|
+
|
|
183
|
+
for (const k of aKeys) {
|
|
184
|
+
if (a?.[k] !== b?.[k]) return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private _resolveFormData(): ResolvedFormData | null {
|
|
191
|
+
if (!this.config.formData) return null;
|
|
192
|
+
|
|
193
|
+
const formData = this.config.formData.includes(':')
|
|
194
|
+
? this.config.formData
|
|
195
|
+
: `${this.config.controller}:${this.config.formData}`;
|
|
196
|
+
|
|
197
|
+
const [controllerName, path] = formData.split(':');
|
|
198
|
+
const controller = ez.getControllerSync(controllerName);
|
|
199
|
+
if (!controller?.state) return null;
|
|
200
|
+
|
|
201
|
+
const props = path.split('.');
|
|
202
|
+
return {
|
|
203
|
+
controller,
|
|
204
|
+
props
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
getFormData(): FormData | null {
|
|
209
|
+
const resolved = this._resolveFormData();
|
|
210
|
+
if (!resolved) return null;
|
|
211
|
+
|
|
212
|
+
return ez.getDeepValue(
|
|
213
|
+
resolved.controller.state,
|
|
214
|
+
resolved.props
|
|
215
|
+
) as FormData | null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
setFormData(data: FormData = {}): void {
|
|
219
|
+
const resolved = this._resolveFormData();
|
|
220
|
+
if (!resolved) return;
|
|
221
|
+
|
|
222
|
+
const target = ez.getDeepValue(resolved.controller.state, resolved.props) as FormData | null;
|
|
223
|
+
if (!target) return;
|
|
224
|
+
|
|
225
|
+
Object.keys(target).forEach(k => delete target[k]);
|
|
226
|
+
Object.entries(data).forEach(([k, v]) => target[k] = v);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private _cloneFormData(obj: unknown): FormData {
|
|
230
|
+
return JSON.parse(JSON.stringify(obj ?? {}));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
resetFormData(): void {
|
|
234
|
+
if (!this._initialFormData) return;
|
|
235
|
+
this.setFormData(this._initialFormData);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private _captureInitialFormData(): void {
|
|
239
|
+
const resolved = this._resolveFormData();
|
|
240
|
+
if (!resolved) return;
|
|
241
|
+
|
|
242
|
+
const { controller, props } = resolved;
|
|
243
|
+
const current = ez.getDeepValue(controller.state, props);
|
|
244
|
+
|
|
245
|
+
this._initialFormData = this._cloneFormData(current);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
validate(): boolean {
|
|
249
|
+
this._errors = {};
|
|
250
|
+
|
|
251
|
+
const data = this.getFormData();
|
|
252
|
+
if (!data) return true;
|
|
253
|
+
|
|
254
|
+
for (const item of this._getFormItems()) {
|
|
255
|
+
const name = item.name;
|
|
256
|
+
if (!name) continue;
|
|
257
|
+
|
|
258
|
+
const value = data[name];
|
|
259
|
+
|
|
260
|
+
if (item.validate) {
|
|
261
|
+
let validateConfig = item.validate;
|
|
262
|
+
|
|
263
|
+
if (typeof validateConfig === 'object' && item.required !== undefined) {
|
|
264
|
+
validateConfig = { required: item.required, ...validateConfig as object };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const result = validateField(value, validateConfig as Parameters<typeof validateField>[1], data);
|
|
268
|
+
if (!result.valid) {
|
|
269
|
+
this._errors[name] = result.message || 'Invalid';
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (!item.validate && item.required) {
|
|
275
|
+
let isRequired = false;
|
|
276
|
+
|
|
277
|
+
if (item.required === true) {
|
|
278
|
+
isRequired = true;
|
|
279
|
+
} else if (typeof item.required === 'function') {
|
|
280
|
+
isRequired = item.required(data);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (isRequired && !EzValidators.required(value)) {
|
|
284
|
+
this._errors[name] = item.requiredMessage || 'This field is required';
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return Object.keys(this._errors).length === 0;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private _getFormItems(items: FormItemConfig[] = this.config.items || [], out: FormItemConfig[] = []): FormItemConfig[] {
|
|
293
|
+
for (const item of items) {
|
|
294
|
+
if (item.name) out.push(item);
|
|
295
|
+
if (Array.isArray(item.items)) {
|
|
296
|
+
this._getFormItems(item.items, out);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private _applyErrors(): void {
|
|
303
|
+
this.el.querySelectorAll('[data-ez-field]').forEach((input: Element) => {
|
|
304
|
+
const name = input.getAttribute('data-ez-field');
|
|
305
|
+
const wrapper = input.closest('.ez-input-group');
|
|
306
|
+
if (!wrapper || !name) return;
|
|
307
|
+
|
|
308
|
+
const errorEl = wrapper.querySelector('.ez-field-error');
|
|
309
|
+
const row = wrapper.querySelector('.ez-input-row');
|
|
310
|
+
|
|
311
|
+
if (this._errors[name]) {
|
|
312
|
+
wrapper.classList.add('has-error');
|
|
313
|
+
if (errorEl) errorEl.textContent = this._errors[name];
|
|
314
|
+
if (row) row.classList.add('ez-error');
|
|
315
|
+
} else {
|
|
316
|
+
wrapper.classList.remove('has-error');
|
|
317
|
+
if (row) row.classList.remove('ez-error');
|
|
318
|
+
if (errorEl) errorEl.textContent = '';
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private _clearErrors(): void {
|
|
324
|
+
this._errors = {};
|
|
325
|
+
|
|
326
|
+
this.el.querySelectorAll('.ez-input-group').forEach((wrapper: Element) => {
|
|
327
|
+
wrapper.classList.remove('has-error');
|
|
328
|
+
|
|
329
|
+
const row = wrapper.querySelector('.ez-input-row');
|
|
330
|
+
if (row) row.classList.remove('ez-error');
|
|
331
|
+
|
|
332
|
+
const errorEl = wrapper.querySelector('.ez-field-error');
|
|
333
|
+
if (errorEl) errorEl.textContent = '';
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private _handleSubmit(): void {
|
|
338
|
+
if (typeof this.config.onSubmit === 'function') {
|
|
339
|
+
this.config.onSubmit(this.getDirtyData(), this.getFormData() || {}, this);
|
|
340
|
+
} else if (typeof this.config.onSubmit === 'string') {
|
|
341
|
+
const controller = ez.getControllerSync(this.config.controller as string);
|
|
342
|
+
const method = controller?.[this.config.onSubmit] as OnSubmitFunction | undefined;
|
|
343
|
+
method?.(this.getDirtyData(), this.getFormData() || {}, this);
|
|
344
|
+
} else {
|
|
345
|
+
throw new Error('EzForm: onSubmit is not defined');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
getDirtyData(): FormData {
|
|
350
|
+
const current = this.getFormData() || {};
|
|
351
|
+
const initial = this._initialFormData || {};
|
|
352
|
+
const dirty: FormData = {};
|
|
353
|
+
|
|
354
|
+
const allKeys = new Set([...Object.keys(initial), ...Object.keys(current)]);
|
|
355
|
+
|
|
356
|
+
for (const key of allKeys) {
|
|
357
|
+
if (current[key] !== initial[key]) {
|
|
358
|
+
dirty[key] = current[key];
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return dirty;
|
|
363
|
+
}
|
|
364
|
+
}
|