@rxdi/forms 0.7.212 → 0.7.214
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 +203 -228
- package/dist/form.array.d.ts +31 -0
- package/dist/form.array.js +122 -0
- package/dist/form.decorator.d.ts +1 -1
- package/dist/form.decorator.js +8 -4
- package/dist/form.group.d.ts +19 -13
- package/dist/form.group.js +148 -31
- package/dist/form.tokens.d.ts +38 -1
- package/dist/form.tokens.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +6 -2
- package/dist/rx-fake.d.ts +0 -34
- package/dist/rx-fake.js +0 -99
package/dist/form.decorator.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Form = Form;
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5
|
+
const rxjs_1 = require("rxjs");
|
|
4
6
|
const form_group_1 = require("./form.group");
|
|
5
|
-
const rx_fake_1 = require("./rx-fake");
|
|
6
7
|
function Form(options = {
|
|
7
8
|
strategy: 'none',
|
|
8
9
|
}) {
|
|
@@ -10,14 +11,17 @@ function Form(options = {
|
|
|
10
11
|
if (!options.name) {
|
|
11
12
|
throw new Error('Missing form name');
|
|
12
13
|
}
|
|
13
|
-
const Destroy = clazz.constructor.prototype.disconnectedCallback ||
|
|
14
|
-
const UpdateFirst = clazz.constructor.prototype.firstUpdated ||
|
|
15
|
-
const Connect = clazz.constructor.prototype.connectedCallback ||
|
|
14
|
+
const Destroy = clazz.constructor.prototype.disconnectedCallback || rxjs_1.noop;
|
|
15
|
+
const UpdateFirst = clazz.constructor.prototype.firstUpdated || rxjs_1.noop;
|
|
16
|
+
const Connect = clazz.constructor.prototype.connectedCallback || rxjs_1.noop;
|
|
16
17
|
clazz.constructor.prototype.connectedCallback = function () {
|
|
17
18
|
if (!(this[name] instanceof form_group_1.FormGroup)) {
|
|
18
19
|
throw new Error('Value provided is not an instance of FormGroup!');
|
|
19
20
|
}
|
|
20
21
|
this[name].setParentElement(this).setOptions(options).prepareValues();
|
|
22
|
+
if (options.model && this[options.model]) {
|
|
23
|
+
this[name].patchValue(this[options.model]);
|
|
24
|
+
}
|
|
21
25
|
return Connect.call(this);
|
|
22
26
|
};
|
|
23
27
|
clazz.constructor.prototype.firstUpdated = function () {
|
package/dist/form.group.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import { FormInputOptions, FormOptions, ErrorObject, AbstractInput } from './form.tokens';
|
|
2
1
|
import { LitElement } from '@rxdi/lit-html';
|
|
2
|
+
import { AbstractControl, AbstractInput, ErrorObject, FormInputOptions, FormOptions, NestedKeyOf, UnwrapValue, ValidatorFn } from './form.tokens';
|
|
3
3
|
export declare class FormGroup<T = FormInputOptions, E = {
|
|
4
4
|
[key: string]: never;
|
|
5
|
-
}> {
|
|
6
|
-
validators: Map<string,
|
|
5
|
+
}> implements AbstractControl<UnwrapValue<T>> {
|
|
6
|
+
validators: Map<string, ValidatorFn[]>;
|
|
7
7
|
valid: boolean;
|
|
8
8
|
invalid: boolean;
|
|
9
|
-
errors: T
|
|
9
|
+
errors: UnwrapValue<T>;
|
|
10
|
+
private controls;
|
|
10
11
|
private readonly _valueChanges;
|
|
11
12
|
private form;
|
|
12
13
|
private errorMap;
|
|
13
14
|
private inputs;
|
|
14
15
|
private options;
|
|
15
16
|
private parentElement;
|
|
17
|
+
private subscriptions;
|
|
16
18
|
constructor(value?: T, errors?: E);
|
|
17
19
|
init(): void;
|
|
18
20
|
prepareValues(): this;
|
|
@@ -20,8 +22,10 @@ export declare class FormGroup<T = FormInputOptions, E = {
|
|
|
20
22
|
getParentElement(): LitElement;
|
|
21
23
|
setOptions(options: FormOptions): this;
|
|
22
24
|
getOptions(): FormOptions;
|
|
23
|
-
get valueChanges(): import("rxjs").Observable<T
|
|
24
|
-
updateValueAndValidity(): Promise<ErrorObject
|
|
25
|
+
get valueChanges(): import("rxjs").Observable<UnwrapValue<T>>;
|
|
26
|
+
updateValueAndValidity(): Promise<(ErrorObject | {
|
|
27
|
+
message: string;
|
|
28
|
+
})[]>;
|
|
25
29
|
private updateValueAndValidityOnEvent;
|
|
26
30
|
applyValidationContext({ errors, element }: ErrorObject): boolean;
|
|
27
31
|
querySelectForm(shadowRoot: HTMLElement | ShadowRoot): HTMLFormElement;
|
|
@@ -31,20 +35,22 @@ export declare class FormGroup<T = FormInputOptions, E = {
|
|
|
31
35
|
setElementValidity(el: AbstractInput, validity?: boolean): Promise<void>;
|
|
32
36
|
setElementDirty(input: AbstractInput): void;
|
|
33
37
|
isInputPresentOnStage(input: AbstractInput): number;
|
|
38
|
+
private getModelKeyName;
|
|
34
39
|
validate(element: AbstractInput): Promise<ErrorObject>;
|
|
35
40
|
private mapInputErrors;
|
|
36
|
-
get(name:
|
|
37
|
-
getError(inputName: keyof T, errorKey:
|
|
38
|
-
hasError(inputName: keyof T, errorKey:
|
|
41
|
+
get<K extends NestedKeyOf<T>>(name: K): AbstractControl | AbstractInput;
|
|
42
|
+
getError(inputName: keyof T, errorKey: string): never;
|
|
43
|
+
hasError(inputName: keyof T, errorKey: string): boolean;
|
|
39
44
|
reset(): void;
|
|
40
45
|
setFormValidity(validity?: boolean): void;
|
|
41
46
|
resetErrors(): void;
|
|
42
|
-
get value(): T
|
|
43
|
-
set value(value: T);
|
|
47
|
+
get value(): UnwrapValue<T>;
|
|
48
|
+
set value(value: UnwrapValue<T>);
|
|
44
49
|
unsubscribe(): void;
|
|
45
50
|
getValue(name: keyof T): T[keyof T];
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
patchValue(value: Partial<UnwrapValue<T>>): void;
|
|
52
|
+
setValue(name: keyof T, value: unknown): void;
|
|
53
|
+
setFormValue(value: UnwrapValue<T>): void;
|
|
48
54
|
setFormElement(form: HTMLFormElement): this;
|
|
49
55
|
setInputs(inputs: AbstractInput[]): void;
|
|
50
56
|
getFormElement(): HTMLFormElement;
|
package/dist/form.group.js
CHANGED
|
@@ -10,34 +10,66 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.FormGroup = void 0;
|
|
13
|
+
const rxjs_1 = require("rxjs");
|
|
13
14
|
const form_tokens_1 = require("./form.tokens");
|
|
14
|
-
const rx_fake_1 = require("./rx-fake");
|
|
15
15
|
class FormGroup {
|
|
16
16
|
constructor(value, errors) {
|
|
17
17
|
this.validators = new Map();
|
|
18
18
|
this.valid = true;
|
|
19
19
|
this.invalid = false;
|
|
20
20
|
this.errors = {};
|
|
21
|
+
this.controls = new Map();
|
|
21
22
|
this.errorMap = new Map();
|
|
22
23
|
this.inputs = new Map();
|
|
23
24
|
this.options = {};
|
|
24
|
-
this.
|
|
25
|
+
this.subscriptions = new Map();
|
|
26
|
+
this._valueChanges = new rxjs_1.BehaviorSubject(value);
|
|
27
|
+
if (value) {
|
|
28
|
+
Object.keys(value).forEach((key) => {
|
|
29
|
+
if (typeof value[key] === 'object' &&
|
|
30
|
+
value[key] !== null &&
|
|
31
|
+
(value[key]['controls'] || value[key]['push']) &&
|
|
32
|
+
value[key]['valueChanges']) {
|
|
33
|
+
// It's likely a FormGroup or FormArray
|
|
34
|
+
const control = value[key];
|
|
35
|
+
if (control.name === '' || control.name === undefined) {
|
|
36
|
+
control.name = key;
|
|
37
|
+
}
|
|
38
|
+
this.controls.set(key, control);
|
|
39
|
+
if (control.valueChanges) {
|
|
40
|
+
this.subscriptions.set(key, control.valueChanges.subscribe(() => {
|
|
41
|
+
this._valueChanges.next(this.value);
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
25
47
|
}
|
|
26
48
|
init() {
|
|
27
49
|
this.setFormElement(this.querySelectForm(this.parentElement.shadowRoot || this.parentElement)).setInputs(this.mapEventToInputs(this.querySelectorAllInputs()));
|
|
50
|
+
this.controls.forEach((c) => {
|
|
51
|
+
if (c.init)
|
|
52
|
+
c.init();
|
|
53
|
+
});
|
|
28
54
|
}
|
|
29
55
|
prepareValues() {
|
|
30
56
|
Object.keys(this.value).forEach((v) => {
|
|
57
|
+
// Skip nested controls
|
|
58
|
+
if (this.controls.has(v))
|
|
59
|
+
return;
|
|
31
60
|
const value = this.value[v];
|
|
32
61
|
this.errors[v] = this.errors[v] || {};
|
|
33
|
-
if (value.constructor === Array) {
|
|
62
|
+
if (value && value.constructor === Array) {
|
|
34
63
|
if (value[1] && value[1].constructor === Array) {
|
|
35
64
|
value[1].forEach((val) => {
|
|
36
65
|
const oldValidators = this.validators.get(v) || [];
|
|
37
66
|
this.validators.set(v, [...oldValidators, val]);
|
|
38
67
|
});
|
|
39
68
|
}
|
|
40
|
-
if (value[0]
|
|
69
|
+
if (value[0] === undefined || value[0] === null) {
|
|
70
|
+
this.value[v] = '';
|
|
71
|
+
}
|
|
72
|
+
else if (value[0].constructor === String ||
|
|
41
73
|
value[0].constructor === Number ||
|
|
42
74
|
value[0].constructor === Boolean) {
|
|
43
75
|
this.value[v] = value[0];
|
|
@@ -51,6 +83,11 @@ class FormGroup {
|
|
|
51
83
|
}
|
|
52
84
|
setParentElement(parent) {
|
|
53
85
|
this.parentElement = parent;
|
|
86
|
+
this.controls.forEach((c) => {
|
|
87
|
+
if (c.setParentElement) {
|
|
88
|
+
c.setParentElement(parent);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
54
91
|
return this;
|
|
55
92
|
}
|
|
56
93
|
getParentElement() {
|
|
@@ -58,6 +95,11 @@ class FormGroup {
|
|
|
58
95
|
}
|
|
59
96
|
setOptions(options) {
|
|
60
97
|
this.options = options;
|
|
98
|
+
this.controls.forEach((c) => {
|
|
99
|
+
if (c.setOptions) {
|
|
100
|
+
c.setOptions(Object.assign(Object.assign({}, options), { namespace: this.options.namespace ? `${this.options.namespace}.${c.name}` : c.name }));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
61
103
|
return this;
|
|
62
104
|
}
|
|
63
105
|
getOptions() {
|
|
@@ -66,6 +108,7 @@ class FormGroup {
|
|
|
66
108
|
get valueChanges() {
|
|
67
109
|
return this._valueChanges.asObservable();
|
|
68
110
|
}
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
69
112
|
updateValueAndValidity() {
|
|
70
113
|
return __awaiter(this, void 0, void 0, function* () {
|
|
71
114
|
this.resetErrors();
|
|
@@ -75,11 +118,21 @@ class FormGroup {
|
|
|
75
118
|
this.setElementDirty(i);
|
|
76
119
|
return yield this.validate(i);
|
|
77
120
|
})));
|
|
121
|
+
for (const [key, control] of this.controls.entries()) {
|
|
122
|
+
if (control.updateValueAndValidity) {
|
|
123
|
+
yield control.updateValueAndValidity();
|
|
124
|
+
if (control.invalid) {
|
|
125
|
+
this.invalid = true;
|
|
126
|
+
this.valid = false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
78
130
|
this.getParentElement().requestUpdate();
|
|
79
|
-
return inputs.filter((e) => e.errors.length);
|
|
131
|
+
return inputs.filter((e) => e.errors.length) || (this.invalid ? [{ message: 'Invalid Form' }] : []);
|
|
80
132
|
});
|
|
81
133
|
}
|
|
82
134
|
updateValueAndValidityOnEvent(method) {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
83
136
|
const self = this;
|
|
84
137
|
return function (event) {
|
|
85
138
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -101,7 +154,7 @@ class FormGroup {
|
|
|
101
154
|
value = Number(value);
|
|
102
155
|
}
|
|
103
156
|
const inputsWithBindings = [
|
|
104
|
-
...
|
|
157
|
+
...self.getFormElement().querySelectorAll(`input[name="${this.name}"]:checked`).values(),
|
|
105
158
|
];
|
|
106
159
|
if (hasMultipleBindings > 1) {
|
|
107
160
|
if (!self.options.multi && this.type === 'checkbox') {
|
|
@@ -117,13 +170,13 @@ class FormGroup {
|
|
|
117
170
|
if (self.options.strict) {
|
|
118
171
|
if (isValid) {
|
|
119
172
|
yield self.setElementValidity(this, isValid);
|
|
120
|
-
self.setValue(this.name, value);
|
|
173
|
+
self.setValue(self.getModelKeyName(this.name), value);
|
|
121
174
|
}
|
|
122
175
|
self.parentElement.requestUpdate();
|
|
123
176
|
return method.call(self.parentElement, event);
|
|
124
177
|
}
|
|
125
178
|
yield self.setElementValidity(this, isValid);
|
|
126
|
-
self.setValue(this.name, value);
|
|
179
|
+
self.setValue(self.getModelKeyName(this.name), value);
|
|
127
180
|
self.parentElement.requestUpdate();
|
|
128
181
|
return method.call(self.parentElement, event);
|
|
129
182
|
});
|
|
@@ -132,18 +185,21 @@ class FormGroup {
|
|
|
132
185
|
applyValidationContext({ errors, element }) {
|
|
133
186
|
const form = this.getFormElement();
|
|
134
187
|
if (errors.length) {
|
|
135
|
-
this.invalid = form
|
|
136
|
-
this.valid = form
|
|
188
|
+
this.invalid = form['invalid'] = true;
|
|
189
|
+
this.valid = form['valid'] = false;
|
|
137
190
|
return false;
|
|
138
191
|
}
|
|
139
192
|
else {
|
|
140
|
-
this.errors[element.name] = {};
|
|
141
|
-
this.invalid = form
|
|
142
|
-
this.valid = form
|
|
193
|
+
this.errors[this.getModelKeyName(element.name)] = {};
|
|
194
|
+
this.invalid = form['invalid'] = !form.checkValidity();
|
|
195
|
+
this.valid = form['valid'] = form.checkValidity();
|
|
143
196
|
return true;
|
|
144
197
|
}
|
|
145
198
|
}
|
|
146
199
|
querySelectForm(shadowRoot) {
|
|
200
|
+
if (this.options['form']) {
|
|
201
|
+
return this.options['form'];
|
|
202
|
+
}
|
|
147
203
|
const form = shadowRoot.querySelector(`form[name="${this.options.name}"]`);
|
|
148
204
|
if (!form) {
|
|
149
205
|
throw new Error(`Form element with name "${this.options.name}" not present inside ${this.getParentElement().outerHTML} component`);
|
|
@@ -155,10 +211,9 @@ class FormGroup {
|
|
|
155
211
|
return form;
|
|
156
212
|
}
|
|
157
213
|
querySelectAll(name) {
|
|
158
|
-
return [
|
|
159
|
-
...this.form.querySelectorAll(name).values(),
|
|
160
|
-
];
|
|
214
|
+
return [...this.form.querySelectorAll(name).values()];
|
|
161
215
|
}
|
|
216
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
162
217
|
querySelectorAllInputs() {
|
|
163
218
|
var _a;
|
|
164
219
|
return [...((_a = this.options.customElements) !== null && _a !== void 0 ? _a : []), 'input', 'select', 'textarea']
|
|
@@ -167,11 +222,14 @@ class FormGroup {
|
|
|
167
222
|
.filter((el) => this.isInputPresentOnStage(el))
|
|
168
223
|
.filter((el) => !!el.name);
|
|
169
224
|
}
|
|
225
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
170
226
|
mapEventToInputs(inputs = []) {
|
|
171
227
|
return inputs.map((el) => {
|
|
172
228
|
const strategy = `on${this.options.strategy}`;
|
|
173
229
|
if (!el[strategy]) {
|
|
174
|
-
el[strategy] = function () {
|
|
230
|
+
el[strategy] = function () {
|
|
231
|
+
//
|
|
232
|
+
};
|
|
175
233
|
}
|
|
176
234
|
const customAttributes = Object.keys(el.attributes)
|
|
177
235
|
.map((k) => (el.attributes[k].name.startsWith('#') ? el.attributes[k] : null))
|
|
@@ -202,20 +260,39 @@ class FormGroup {
|
|
|
202
260
|
}
|
|
203
261
|
isInputPresentOnStage(input) {
|
|
204
262
|
if (input.outerHTML === '<input type="submit" style="display: none;">') {
|
|
205
|
-
return;
|
|
263
|
+
return 0;
|
|
206
264
|
}
|
|
207
|
-
const
|
|
265
|
+
const keyIndex = this.getModelKeyName(input.name);
|
|
266
|
+
const isInputPresent = Object.keys(this.value).filter((v) => v === keyIndex);
|
|
208
267
|
return isInputPresent.length;
|
|
209
268
|
}
|
|
269
|
+
getModelKeyName(domName) {
|
|
270
|
+
if (this.options['namespace']) {
|
|
271
|
+
// pattern: namespace[key] or namespace.key
|
|
272
|
+
// Example: allowedIps[0].ip -> namespace=allowedIps[0] -> key=ip
|
|
273
|
+
if (domName.startsWith(this.options['namespace'])) {
|
|
274
|
+
const suffix = domName.replace(this.options['namespace'], '');
|
|
275
|
+
// Handle .key or [key]
|
|
276
|
+
if (suffix.startsWith('.')) {
|
|
277
|
+
return suffix.substring(1);
|
|
278
|
+
}
|
|
279
|
+
if (suffix.startsWith('[')) {
|
|
280
|
+
return suffix.substring(1, suffix.length - 1); // Not dealing with that yet
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return domName;
|
|
284
|
+
}
|
|
285
|
+
return domName;
|
|
286
|
+
}
|
|
287
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
210
288
|
validate(element) {
|
|
211
289
|
return __awaiter(this, void 0, void 0, function* () {
|
|
212
290
|
let errors = [];
|
|
213
291
|
element.setCustomValidity('');
|
|
214
|
-
this.setFormValidity(true);
|
|
215
292
|
if (!element.checkValidity()) {
|
|
216
293
|
return {
|
|
217
294
|
errors: errors.concat(Object.keys(form_tokens_1.InputValidityState)
|
|
218
|
-
.map((key) => element.validity[key] ? { key, message: element.validationMessage } : null)
|
|
295
|
+
.map((key) => (element.validity[key] ? { key, message: element.validationMessage } : null))
|
|
219
296
|
.filter((i) => !!i)),
|
|
220
297
|
element,
|
|
221
298
|
};
|
|
@@ -224,32 +301,44 @@ class FormGroup {
|
|
|
224
301
|
if (!errors.length) {
|
|
225
302
|
return { errors: [], element };
|
|
226
303
|
}
|
|
227
|
-
this.setFormValidity(false);
|
|
228
304
|
element.setCustomValidity(errors[0].message);
|
|
229
305
|
return { element, errors };
|
|
230
306
|
});
|
|
231
307
|
}
|
|
308
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
232
309
|
mapInputErrors(element) {
|
|
233
310
|
return __awaiter(this, void 0, void 0, function* () {
|
|
234
|
-
const
|
|
235
|
-
|
|
311
|
+
const modelKey = this.getModelKeyName(element.name);
|
|
312
|
+
const res = yield Promise.all((this.validators.get(modelKey) || []).map((v) => __awaiter(this, void 0, void 0, function* () {
|
|
313
|
+
this.errors[modelKey] = this.errors[modelKey] || {};
|
|
236
314
|
const error = yield v.bind(this.getParentElement())(element);
|
|
237
315
|
// if (error) {
|
|
238
316
|
// element.focus();
|
|
239
317
|
// }
|
|
240
318
|
if (error && error.key) {
|
|
241
|
-
this.errors[
|
|
319
|
+
this.errors[modelKey][error.key] = error.message;
|
|
242
320
|
this.errorMap.set(v, error.key);
|
|
243
321
|
return { key: error.key, message: error.message };
|
|
244
322
|
}
|
|
245
323
|
else if (this.errorMap.has(v)) {
|
|
246
|
-
delete this.errors[
|
|
324
|
+
delete this.errors[modelKey][this.errorMap.get(v)];
|
|
247
325
|
}
|
|
248
326
|
})));
|
|
249
327
|
return res.filter((i) => !!i);
|
|
250
328
|
});
|
|
251
329
|
}
|
|
252
330
|
get(name) {
|
|
331
|
+
if (this.controls.has(name)) {
|
|
332
|
+
return this.controls.get(name);
|
|
333
|
+
}
|
|
334
|
+
if (String(name).includes('.')) {
|
|
335
|
+
const names = String(name).split('.');
|
|
336
|
+
const key = names.shift();
|
|
337
|
+
const control = this.controls.get(key);
|
|
338
|
+
if (control && control.get) {
|
|
339
|
+
return control.get(names.join('.'));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
253
342
|
return this.inputs.get(name);
|
|
254
343
|
}
|
|
255
344
|
getError(inputName, errorKey) {
|
|
@@ -277,7 +366,11 @@ class FormGroup {
|
|
|
277
366
|
this.errorMap.clear();
|
|
278
367
|
}
|
|
279
368
|
get value() {
|
|
280
|
-
|
|
369
|
+
const values = this._valueChanges.getValue();
|
|
370
|
+
this.controls.forEach((control, key) => {
|
|
371
|
+
values[key] = control.value;
|
|
372
|
+
});
|
|
373
|
+
return values;
|
|
281
374
|
}
|
|
282
375
|
set value(value) {
|
|
283
376
|
this._valueChanges.next(value);
|
|
@@ -285,16 +378,35 @@ class FormGroup {
|
|
|
285
378
|
unsubscribe() {
|
|
286
379
|
this.reset();
|
|
287
380
|
this._valueChanges.unsubscribe();
|
|
381
|
+
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
382
|
+
this.subscriptions.clear();
|
|
383
|
+
this.controls.forEach((c) => { var _a; return (_a = c.unsubscribe) === null || _a === void 0 ? void 0 : _a.call(c); });
|
|
288
384
|
}
|
|
289
385
|
getValue(name) {
|
|
290
386
|
return this.value[name];
|
|
291
387
|
}
|
|
388
|
+
patchValue(value) {
|
|
389
|
+
if (!value) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
Object.keys(value).forEach((key) => {
|
|
393
|
+
if (this.controls.has(key) && this.controls.get(key)['patchValue']) {
|
|
394
|
+
this.controls.get(key)['patchValue'](value[key]);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
this.setValue(key, value[key]);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
}
|
|
292
401
|
setValue(name, value) {
|
|
293
402
|
const input = this.get(name);
|
|
294
403
|
if (!input) {
|
|
295
|
-
|
|
404
|
+
// If no input, maybe just set the value in model?
|
|
405
|
+
// User code had return; but we might want to update model even if no input?
|
|
406
|
+
// return;
|
|
296
407
|
}
|
|
297
|
-
input.value
|
|
408
|
+
if (input && input.value !== undefined)
|
|
409
|
+
input.value = value;
|
|
298
410
|
const values = this.value;
|
|
299
411
|
values[name] = value;
|
|
300
412
|
this.value = values;
|
|
@@ -304,12 +416,17 @@ class FormGroup {
|
|
|
304
416
|
}
|
|
305
417
|
setFormElement(form) {
|
|
306
418
|
this.form = form;
|
|
419
|
+
this.controls.forEach((c) => {
|
|
420
|
+
if (c.setFormElement)
|
|
421
|
+
c.setFormElement(form);
|
|
422
|
+
});
|
|
307
423
|
return this;
|
|
308
424
|
}
|
|
309
425
|
setInputs(inputs) {
|
|
310
426
|
this.inputs = new Map(inputs.map((e) => {
|
|
311
|
-
|
|
312
|
-
|
|
427
|
+
const key = this.getModelKeyName(e.name);
|
|
428
|
+
e.value = this.getValue(key);
|
|
429
|
+
return [key, e];
|
|
313
430
|
}));
|
|
314
431
|
}
|
|
315
432
|
getFormElement() {
|
package/dist/form.tokens.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import { LitElement } from '@rxdi/lit-html';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
export type UnwrapValue<T> = T extends AbstractControl<infer U> ? U : T extends {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
} ? {
|
|
6
|
+
[K in keyof T]: UnwrapValue<T[K]>;
|
|
7
|
+
} : T;
|
|
8
|
+
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...0[]];
|
|
9
|
+
export type NestedKeyOf<T, D extends number = 3> = [D] extends [0] ? never : T extends object ? {
|
|
10
|
+
[K in keyof T & (string | number)]: T[K] extends AbstractControl<infer U> ? U extends object ? `${K}` | `${K}.${NestedKeyOf<U, Prev[D]>}` : `${K}` : T[K] extends object ? `${K}` | `${K}.${NestedKeyOf<T[K], Prev[D]>}` : `${K}`;
|
|
11
|
+
}[keyof T & (string | number)] : never;
|
|
1
12
|
export type FormStrategies = keyof WindowEventMap;
|
|
2
13
|
export interface FormOptions {
|
|
3
14
|
/** Name of the form element */
|
|
@@ -14,9 +25,34 @@ export interface FormOptions {
|
|
|
14
25
|
* Example can be found here https://gist.github.com/Stradivario/57acf0fa19900867a7f55b0f01251d6e
|
|
15
26
|
* */
|
|
16
27
|
customElements?: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Internal property for handling nested forms.
|
|
30
|
+
*/
|
|
31
|
+
namespace?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Property name of the model to bind to the form
|
|
34
|
+
*/
|
|
35
|
+
model?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface AbstractControl<T = any> {
|
|
38
|
+
setOptions(options: FormOptions): this | void;
|
|
39
|
+
getOptions(): FormOptions;
|
|
40
|
+
init(): void;
|
|
41
|
+
setParentElement(parent: LitElement): this | void;
|
|
42
|
+
setFormElement(form: HTMLFormElement): this | void;
|
|
43
|
+
unsubscribe(): void;
|
|
44
|
+
valueChanges: Observable<T>;
|
|
45
|
+
value: T;
|
|
46
|
+
valid: boolean;
|
|
47
|
+
invalid: boolean;
|
|
48
|
+
updateValueAndValidity?(): Promise<any>;
|
|
49
|
+
name?: string;
|
|
50
|
+
push?(control: AbstractControl): void;
|
|
51
|
+
getFormElement?(): HTMLFormElement;
|
|
17
52
|
}
|
|
53
|
+
export type ValidatorFn = (element: AbstractInput | HTMLInputElement) => Promise<InputErrorMessage | void> | InputErrorMessage | void;
|
|
18
54
|
export interface FormInputOptions {
|
|
19
|
-
[key: string]: [string,
|
|
55
|
+
[key: string]: [string | number | boolean | Date, ValidatorFn[]];
|
|
20
56
|
}
|
|
21
57
|
export interface InputErrorMessage<T = any> {
|
|
22
58
|
key: T;
|
|
@@ -46,3 +82,4 @@ export declare const InputValidityState: {
|
|
|
46
82
|
valueMissing: "valueMissing";
|
|
47
83
|
};
|
|
48
84
|
export type InputValidityState = keyof typeof InputValidityState;
|
|
85
|
+
export {};
|
package/dist/form.tokens.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./form.decorator"), exports);
|
|
18
18
|
__exportStar(require("./form.group"), exports);
|
|
19
19
|
__exportStar(require("./form.tokens"), exports);
|
|
20
|
+
__exportStar(require("./form.array"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rxdi/forms",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.214",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"author": "Kristiyan Tachev",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,11 +12,15 @@
|
|
|
12
12
|
"build": "tsc"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@rxdi/lit-html": "^0.7.
|
|
15
|
+
"@rxdi/lit-html": "^0.7.213",
|
|
16
16
|
"@types/node": "^25.0.3",
|
|
17
17
|
"rxjs": "^7.8.2",
|
|
18
18
|
"typescript": "^5.9.3"
|
|
19
19
|
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"rxjs": "^7.8.2",
|
|
22
|
+
"@rxdi/lit-html": "*"
|
|
23
|
+
},
|
|
20
24
|
"types": "./dist/index.d.ts",
|
|
21
25
|
"module": "./dist/index.js",
|
|
22
26
|
"typings": "./dist/index.d.ts"
|
package/dist/rx-fake.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject as BS, Observable as O, Subscription as S } from 'rxjs';
|
|
2
|
-
type OBS<T> = (o: $Observable<T>) => void | Function;
|
|
3
|
-
type FN<T> = (a: T) => void;
|
|
4
|
-
export declare class $Subscription<T> {
|
|
5
|
-
o: Map<Function, FN<T>>;
|
|
6
|
-
unsubscribe(): void;
|
|
7
|
-
}
|
|
8
|
-
export declare class $Observable<T> extends $Subscription<T> {
|
|
9
|
-
fn: OBS<T>;
|
|
10
|
-
init: boolean;
|
|
11
|
-
constructor(fn?: OBS<T>);
|
|
12
|
-
subscribe(c: FN<T>): $Subscription<T>;
|
|
13
|
-
complete(): void;
|
|
14
|
-
next(s: T): void;
|
|
15
|
-
}
|
|
16
|
-
export declare class $BehaviorSubject<T> extends $Observable<T> {
|
|
17
|
-
v: T;
|
|
18
|
-
constructor(v: T);
|
|
19
|
-
private setValue;
|
|
20
|
-
next(s: T): void;
|
|
21
|
-
getValue(): T;
|
|
22
|
-
asObservable(): this;
|
|
23
|
-
}
|
|
24
|
-
export declare function noop(): void;
|
|
25
|
-
export declare function BehaviorSubject<T>(init: T): void;
|
|
26
|
-
export declare function Observable<T>(fn?: OBS<T>): void;
|
|
27
|
-
export declare function Subscription<T>(): void;
|
|
28
|
-
export interface BehaviorSubject<T> extends BS<T> {
|
|
29
|
-
}
|
|
30
|
-
export interface Observable<T> extends O<T> {
|
|
31
|
-
}
|
|
32
|
-
export interface Subscription extends S {
|
|
33
|
-
}
|
|
34
|
-
export {};
|