@relax.js/core 1.0.3 → 1.0.5
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 +194 -188
- package/dist/DependencyInjection.d.ts +45 -27
- package/dist/collections/LinkedList.d.ts +9 -8
- package/dist/collections/index.js +1 -1
- package/dist/collections/index.js.map +3 -3
- package/dist/collections/index.mjs +1 -1
- package/dist/collections/index.mjs.map +3 -3
- package/dist/di/index.js +1 -1
- package/dist/di/index.js.map +3 -3
- package/dist/di/index.mjs +1 -1
- package/dist/di/index.mjs.map +3 -3
- package/dist/elements/index.js +1 -1
- package/dist/elements/index.js.map +1 -1
- package/dist/errors.d.ts +20 -0
- package/dist/forms/FormValidator.d.ts +3 -22
- package/dist/forms/ValidationRules.d.ts +4 -6
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.js.map +4 -4
- package/dist/forms/index.mjs +1 -1
- package/dist/forms/index.mjs.map +4 -4
- package/dist/forms/setFormData.d.ts +39 -1
- package/dist/html/TableRenderer.d.ts +1 -0
- package/dist/html/index.js +1 -1
- package/dist/html/index.js.map +3 -3
- package/dist/html/index.mjs +1 -1
- package/dist/html/index.mjs.map +3 -3
- package/dist/html/template.d.ts +4 -0
- package/dist/http/ServerSentEvents.d.ts +1 -1
- package/dist/http/SimpleWebSocket.d.ts +1 -1
- package/dist/http/http.d.ts +1 -0
- package/dist/http/index.js +1 -1
- package/dist/http/index.js.map +3 -3
- package/dist/http/index.mjs +1 -1
- package/dist/http/index.mjs.map +3 -3
- package/dist/i18n/icu.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/index.js.map +2 -2
- package/dist/i18n/index.mjs +1 -1
- package/dist/i18n/index.mjs.map +2 -2
- package/dist/index.js +3 -3
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +3 -3
- package/dist/routing/NavigateRouteEvent.d.ts +4 -4
- package/dist/routing/index.js +3 -3
- package/dist/routing/index.js.map +3 -3
- package/dist/routing/index.mjs +3 -3
- package/dist/routing/index.mjs.map +3 -3
- package/dist/routing/navigation.d.ts +1 -1
- package/dist/routing/routeTargetRegistry.d.ts +1 -0
- package/dist/routing/types.d.ts +2 -1
- package/dist/templates/NodeTemplate.d.ts +3 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +3 -3
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/index.mjs.map +3 -3
- package/docs/Architecture.md +333 -333
- package/docs/DependencyInjection.md +277 -237
- package/docs/Errors.md +87 -87
- package/docs/GettingStarted.md +238 -231
- package/docs/Pipes.md +5 -5
- package/docs/Translations.md +167 -312
- package/docs/WhyRelaxjs.md +336 -336
- package/docs/api.json +93193 -0
- package/docs/elements/dom.md +102 -102
- package/docs/forms/creating-form-components.md +924 -924
- package/docs/forms/form-api.md +94 -94
- package/docs/forms/forms.md +99 -99
- package/docs/forms/patterns.md +311 -311
- package/docs/forms/reading-writing.md +465 -365
- package/docs/forms/validation.md +351 -351
- package/docs/html/TableRenderer.md +291 -291
- package/docs/html/html.md +175 -175
- package/docs/html/index.md +54 -54
- package/docs/html/template.md +422 -422
- package/docs/http/HttpClient.md +459 -459
- package/docs/http/ServerSentEvents.md +184 -184
- package/docs/http/index.md +109 -109
- package/docs/i18n/i18n.md +49 -4
- package/docs/i18n/intl-standard.md +178 -178
- package/docs/routing/RouteLink.md +98 -98
- package/docs/routing/Routing.md +332 -332
- package/docs/routing/layouts.md +207 -207
- package/docs/setup/bootstrapping.md +154 -0
- package/docs/setup/build-and-deploy.md +183 -0
- package/docs/setup/project-structure.md +170 -0
- package/docs/setup/vite.md +175 -0
- package/docs/utilities.md +143 -143
- package/package.json +4 -2
|
@@ -1,365 +1,465 @@
|
|
|
1
|
-
# Reading & Writing Form Data
|
|
2
|
-
|
|
3
|
-
Functions for reading and writing form data with automatic type conversion.
|
|
4
|
-
|
|
5
|
-
## mapFormToClass
|
|
6
|
-
|
|
7
|
-
Maps form field values to a class instance's properties with type conversion. Provides full type safety by populating an existing typed object.
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
import { mapFormToClass } from '
|
|
11
|
-
|
|
12
|
-
class UserDTO {
|
|
13
|
-
name: string = '';
|
|
14
|
-
email: string = '';
|
|
15
|
-
age: number = 0;
|
|
16
|
-
newsletter: boolean = false;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const form = document.querySelector('form');
|
|
20
|
-
const user = mapFormToClass(form, new UserDTO());
|
|
21
|
-
console.log(user.name, user.age, user.newsletter);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Options
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
// Options object (inline, not a named interface)
|
|
28
|
-
{
|
|
29
|
-
throwOnMissingProperty?: boolean; // Throw if form field has no matching property
|
|
30
|
-
throwOnMissingField?: boolean; // Throw if class property has no matching field
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Strict Validation Mode
|
|
35
|
-
|
|
36
|
-
Catch mismatches between form fields and your data model:
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
const user = mapFormToClass(form, new UserDTO(), {
|
|
40
|
-
throwOnMissingProperty: true, // Catch typos in form field names
|
|
41
|
-
throwOnMissingField: true // Ensure all DTO fields are in form
|
|
42
|
-
});
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Type Conversion
|
|
46
|
-
|
|
47
|
-
Automatic conversion based on input types:
|
|
48
|
-
|
|
49
|
-
| Input Type | Converted To |
|
|
50
|
-
|------------|--------------|
|
|
51
|
-
| `checkbox` | `boolean` |
|
|
52
|
-
| `number` | `number` |
|
|
53
|
-
| `date` | `Date` |
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
class ProductDTO {
|
|
57
|
-
name: string = '';
|
|
58
|
-
price: number = 0;
|
|
59
|
-
inStock: boolean = false;
|
|
60
|
-
releaseDate: Date | null = null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const product = mapFormToClass(form, new ProductDTO());
|
|
64
|
-
// product.price is number, product.inStock is boolean
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## readData
|
|
68
|
-
|
|
69
|
-
Reads all form data into a plain object with automatic type conversion. Use when you don't need strict typing.
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
import { readData } from '
|
|
73
|
-
|
|
74
|
-
const form = document.querySelector('form');
|
|
75
|
-
const data = readData(form);
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### Type Conversion
|
|
79
|
-
|
|
80
|
-
Type conversion is determined by:
|
|
81
|
-
1. `data-type` attribute if present (`number`, `boolean`, `string`, `Date`)
|
|
82
|
-
2. Input type (`checkbox`, `number`, `date`, etc.)
|
|
83
|
-
3. Falls back to string
|
|
84
|
-
|
|
85
|
-
```html
|
|
86
|
-
<form>
|
|
87
|
-
<input name="username" value="john" />
|
|
88
|
-
<input name="age" type="number" value="25" />
|
|
89
|
-
<input name="active" type="checkbox" checked />
|
|
90
|
-
<input name="salary" data-type="number" value="50000" />
|
|
91
|
-
<select name="colors" multiple>
|
|
92
|
-
<option value="red" selected>Red</option>
|
|
93
|
-
<option value="blue" selected>Blue</option>
|
|
94
|
-
</select>
|
|
95
|
-
</form>
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
const data = readData(form);
|
|
100
|
-
// Returns: {
|
|
101
|
-
// username: 'john',
|
|
102
|
-
// age: 25,
|
|
103
|
-
// active: true,
|
|
104
|
-
// salary: 50000,
|
|
105
|
-
// colors: ['red', 'blue']
|
|
106
|
-
// }
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Checkbox Handling
|
|
110
|
-
|
|
111
|
-
Unchecked checkboxes are included as `false` in the result. Checked checkboxes with no explicit `value` attribute (which submit as `'on'` in FormData) are correctly converted to `true`.
|
|
112
|
-
|
|
113
|
-
```html
|
|
114
|
-
<input name="active" type="checkbox" checked />
|
|
115
|
-
<input name="terms" type="checkbox" />
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
const data = readData(form);
|
|
120
|
-
// Returns: { active: true, terms: false }
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Custom Form Components
|
|
124
|
-
|
|
125
|
-
Works with form-associated custom elements:
|
|
126
|
-
|
|
127
|
-
```html
|
|
128
|
-
<form>
|
|
129
|
-
<r-input name="email" value="test@example.com"></r-input>
|
|
130
|
-
<r-checkbox name="terms" checked></r-checkbox>
|
|
131
|
-
</form>
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
const data = readData(form);
|
|
136
|
-
// Returns: { email: 'test@example.com', terms: true }
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## setFormData
|
|
140
|
-
|
|
141
|
-
Populates form fields from a data object using the `name` attribute.
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
import { setFormData } from '
|
|
145
|
-
|
|
146
|
-
const form = document.querySelector('form');
|
|
147
|
-
const data = { name: 'John', email: 'john@example.com' };
|
|
148
|
-
setFormData(form, data);
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Nested Objects (Dot Notation)
|
|
152
|
-
|
|
153
|
-
```html
|
|
154
|
-
<form>
|
|
155
|
-
<input name="user.name" />
|
|
156
|
-
<input name="user.contact.email" />
|
|
157
|
-
</form>
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
const data = {
|
|
162
|
-
user: {
|
|
163
|
-
name: 'John',
|
|
164
|
-
contact: {
|
|
165
|
-
email: 'john@example.com'
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
setFormData(form, data);
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Date and DateTime
|
|
173
|
-
|
|
174
|
-
`setFormData` formats `Date` objects to the correct string format for each input type:
|
|
175
|
-
|
|
176
|
-
```html
|
|
177
|
-
<input type="date" name="birthday" />
|
|
178
|
-
<input type="datetime-local" name="meeting" />
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
setFormData(form, {
|
|
183
|
-
birthday: new Date('2000-01-15'), // Sets "2000-01-15"
|
|
184
|
-
meeting: new Date('2024-06-15T14:30') // Sets "2024-06-15T14:30"
|
|
185
|
-
});
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Select
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
1
|
+
# Reading & Writing Form Data
|
|
2
|
+
|
|
3
|
+
Functions for reading and writing form data with automatic type conversion.
|
|
4
|
+
|
|
5
|
+
## mapFormToClass
|
|
6
|
+
|
|
7
|
+
Maps form field values to a class instance's properties with type conversion. Provides full type safety by populating an existing typed object.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { mapFormToClass } from '@relax.js/core/forms';
|
|
11
|
+
|
|
12
|
+
class UserDTO {
|
|
13
|
+
name: string = '';
|
|
14
|
+
email: string = '';
|
|
15
|
+
age: number = 0;
|
|
16
|
+
newsletter: boolean = false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const form = document.querySelector('form');
|
|
20
|
+
const user = mapFormToClass(form, new UserDTO());
|
|
21
|
+
console.log(user.name, user.age, user.newsletter);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Options
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// Options object (inline, not a named interface)
|
|
28
|
+
{
|
|
29
|
+
throwOnMissingProperty?: boolean; // Throw if form field has no matching property
|
|
30
|
+
throwOnMissingField?: boolean; // Throw if class property has no matching field
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Strict Validation Mode
|
|
35
|
+
|
|
36
|
+
Catch mismatches between form fields and your data model:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const user = mapFormToClass(form, new UserDTO(), {
|
|
40
|
+
throwOnMissingProperty: true, // Catch typos in form field names
|
|
41
|
+
throwOnMissingField: true // Ensure all DTO fields are in form
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Type Conversion
|
|
46
|
+
|
|
47
|
+
Automatic conversion based on input types:
|
|
48
|
+
|
|
49
|
+
| Input Type | Converted To |
|
|
50
|
+
|------------|--------------|
|
|
51
|
+
| `checkbox` | `boolean` |
|
|
52
|
+
| `number` | `number` |
|
|
53
|
+
| `date` | `Date` |
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
class ProductDTO {
|
|
57
|
+
name: string = '';
|
|
58
|
+
price: number = 0;
|
|
59
|
+
inStock: boolean = false;
|
|
60
|
+
releaseDate: Date | null = null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const product = mapFormToClass(form, new ProductDTO());
|
|
64
|
+
// product.price is number, product.inStock is boolean
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## readData
|
|
68
|
+
|
|
69
|
+
Reads all form data into a plain object with automatic type conversion. Use when you don't need strict typing.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { readData } from '@relax.js/core/forms';
|
|
73
|
+
|
|
74
|
+
const form = document.querySelector('form');
|
|
75
|
+
const data = readData(form);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Type Conversion
|
|
79
|
+
|
|
80
|
+
Type conversion is determined by:
|
|
81
|
+
1. `data-type` attribute if present (`number`, `boolean`, `string`, `Date`)
|
|
82
|
+
2. Input type (`checkbox`, `number`, `date`, etc.)
|
|
83
|
+
3. Falls back to string
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<form>
|
|
87
|
+
<input name="username" value="john" />
|
|
88
|
+
<input name="age" type="number" value="25" />
|
|
89
|
+
<input name="active" type="checkbox" checked />
|
|
90
|
+
<input name="salary" data-type="number" value="50000" />
|
|
91
|
+
<select name="colors" multiple>
|
|
92
|
+
<option value="red" selected>Red</option>
|
|
93
|
+
<option value="blue" selected>Blue</option>
|
|
94
|
+
</select>
|
|
95
|
+
</form>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const data = readData(form);
|
|
100
|
+
// Returns: {
|
|
101
|
+
// username: 'john',
|
|
102
|
+
// age: 25,
|
|
103
|
+
// active: true,
|
|
104
|
+
// salary: 50000,
|
|
105
|
+
// colors: ['red', 'blue']
|
|
106
|
+
// }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Checkbox Handling
|
|
110
|
+
|
|
111
|
+
Unchecked checkboxes are included as `false` in the result. Checked checkboxes with no explicit `value` attribute (which submit as `'on'` in FormData) are correctly converted to `true`.
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
<input name="active" type="checkbox" checked />
|
|
115
|
+
<input name="terms" type="checkbox" />
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const data = readData(form);
|
|
120
|
+
// Returns: { active: true, terms: false }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Custom Form Components
|
|
124
|
+
|
|
125
|
+
Works with form-associated custom elements:
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<form>
|
|
129
|
+
<r-input name="email" value="test@example.com"></r-input>
|
|
130
|
+
<r-checkbox name="terms" checked></r-checkbox>
|
|
131
|
+
</form>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
const data = readData(form);
|
|
136
|
+
// Returns: { email: 'test@example.com', terms: true }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## setFormData
|
|
140
|
+
|
|
141
|
+
Populates form fields from a data object using the `name` attribute.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { setFormData } from '@relax.js/core/forms';
|
|
145
|
+
|
|
146
|
+
const form = document.querySelector('form');
|
|
147
|
+
const data = { name: 'John', email: 'john@example.com' };
|
|
148
|
+
setFormData(form, data);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Nested Objects (Dot Notation)
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<form>
|
|
155
|
+
<input name="user.name" />
|
|
156
|
+
<input name="user.contact.email" />
|
|
157
|
+
</form>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const data = {
|
|
162
|
+
user: {
|
|
163
|
+
name: 'John',
|
|
164
|
+
contact: {
|
|
165
|
+
email: 'john@example.com'
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
setFormData(form, data);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Date and DateTime
|
|
173
|
+
|
|
174
|
+
`setFormData` formats `Date` objects to the correct string format for each input type:
|
|
175
|
+
|
|
176
|
+
```html
|
|
177
|
+
<input type="date" name="birthday" />
|
|
178
|
+
<input type="datetime-local" name="meeting" />
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
setFormData(form, {
|
|
183
|
+
birthday: new Date('2000-01-15'), // Sets "2000-01-15"
|
|
184
|
+
meeting: new Date('2024-06-15T14:30') // Sets "2024-06-15T14:30"
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Select (Single)
|
|
189
|
+
|
|
190
|
+
`setFormData` can both **populate options** and **select a value** on a `<select>`.
|
|
191
|
+
|
|
192
|
+
- The selected value comes from `data` (second argument).
|
|
193
|
+
- The options come from `context` (optional third argument). If `context` is not provided, options must already exist in the DOM.
|
|
194
|
+
- The data value is compared as a string against each option's `value` attribute. If no option matches, nothing is selected.
|
|
195
|
+
|
|
196
|
+
#### Existing options in the DOM
|
|
197
|
+
|
|
198
|
+
```html
|
|
199
|
+
<select name="country">
|
|
200
|
+
<option value="se">Sweden</option>
|
|
201
|
+
<option value="us">United States</option>
|
|
202
|
+
</select>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
setFormData(form, { country: 'se' });
|
|
207
|
+
// Selects the "Sweden" option
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### Populating options from `context`
|
|
211
|
+
|
|
212
|
+
Pass the collection on a third argument. By convention, the property name in `context` matches the select's `name` attribute. Items use a `{ value, text }` shape.
|
|
213
|
+
|
|
214
|
+
```html
|
|
215
|
+
<select name="country"></select>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
setFormData(form, { country: 'se' }, {
|
|
220
|
+
country: [
|
|
221
|
+
{ value: 'se', text: 'Sweden' },
|
|
222
|
+
{ value: 'us', text: 'United States' }
|
|
223
|
+
]
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
A plain string array also works — each string becomes both the value and the text:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
setFormData(form, { country: 'Sweden' }, {
|
|
231
|
+
country: ['Sweden', 'United States']
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### Using `data-source` for custom property names
|
|
236
|
+
|
|
237
|
+
When your collection has different property names (like `id` and `name`), declare them on the select:
|
|
238
|
+
|
|
239
|
+
```html
|
|
240
|
+
<select name="country" data-source="countries(id, name)"></select>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
setFormData(form, { country: 2 }, {
|
|
245
|
+
countries: [
|
|
246
|
+
{ id: 1, name: 'Sweden' },
|
|
247
|
+
{ id: 2, name: 'United States' }
|
|
248
|
+
]
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The `data-source` attribute has two parts:
|
|
253
|
+
|
|
254
|
+
- **Source name** (required): the property on `context` to read from — `countries` above.
|
|
255
|
+
- **Value and text properties** (optional): inside parentheses, separated by a comma — `(id, name)` means `item.id` is the option value and `item.name` is the option text. Without parentheses, the defaults `value` and `text` are used.
|
|
256
|
+
|
|
257
|
+
#### `data-source` as a method
|
|
258
|
+
|
|
259
|
+
The property on `context` can be a method. It is called with no arguments and must return an array:
|
|
260
|
+
|
|
261
|
+
```html
|
|
262
|
+
<select name="country" data-source="getCountries"></select>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
setFormData(form, { country: 'se' }, {
|
|
267
|
+
getCountries: () => [
|
|
268
|
+
{ value: 'se', text: 'Sweden' },
|
|
269
|
+
{ value: 'us', text: 'United States' }
|
|
270
|
+
]
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### Placeholder options are preserved
|
|
275
|
+
|
|
276
|
+
Options whose `value` is empty (for example a leading "Select one…") are kept when `setFormData` repopulates the list:
|
|
277
|
+
|
|
278
|
+
```html
|
|
279
|
+
<select name="country">
|
|
280
|
+
<option value="">Select one…</option>
|
|
281
|
+
</select>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
After calling `setFormData` with a `context`, the placeholder stays at the top and the new options are appended after it.
|
|
285
|
+
|
|
286
|
+
### Select Multiple
|
|
287
|
+
|
|
288
|
+
Works the same way as single selects. The `data` value must be an array. Options can be populated from `context` using either the name convention or `data-source`.
|
|
289
|
+
|
|
290
|
+
```html
|
|
291
|
+
<select name="colors" multiple>
|
|
292
|
+
<option value="red">Red</option>
|
|
293
|
+
<option value="green">Green</option>
|
|
294
|
+
<option value="blue">Blue</option>
|
|
295
|
+
</select>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
setFormData(form, { colors: ['red', 'blue'] });
|
|
300
|
+
// Selects "red" and "blue", deselects "green"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Each array item is compared as a string against each option's `value` attribute. Options that don't match any array item are deselected.
|
|
304
|
+
|
|
305
|
+
### Simple Arrays ([] Notation)
|
|
306
|
+
|
|
307
|
+
For checkboxes, multi-select, and text inputs:
|
|
308
|
+
|
|
309
|
+
```html
|
|
310
|
+
<form>
|
|
311
|
+
<input name="hobbies[]" type="checkbox" value="Reading" />
|
|
312
|
+
<input name="hobbies[]" type="checkbox" value="Cycling" />
|
|
313
|
+
<input name="hobbies[]" type="checkbox" value="Cooking" />
|
|
314
|
+
</form>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
const data = {
|
|
319
|
+
hobbies: ['Reading', 'Cooking']
|
|
320
|
+
};
|
|
321
|
+
setFormData(form, data);
|
|
322
|
+
// Checks "Reading" and "Cooking" checkboxes
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Array of Objects (Indexed Notation)
|
|
326
|
+
|
|
327
|
+
```html
|
|
328
|
+
<form>
|
|
329
|
+
<input name="users[0].name" />
|
|
330
|
+
<input name="users[0].email" />
|
|
331
|
+
<input name="users[1].name" />
|
|
332
|
+
<input name="users[1].email" />
|
|
333
|
+
</form>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
const data = {
|
|
338
|
+
users: [
|
|
339
|
+
{ name: 'John', email: 'john@example.com' },
|
|
340
|
+
{ name: 'Jane', email: 'jane@example.com' }
|
|
341
|
+
]
|
|
342
|
+
};
|
|
343
|
+
setFormData(form, data);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Complex Data Structures
|
|
347
|
+
|
|
348
|
+
```html
|
|
349
|
+
<form id="product-form">
|
|
350
|
+
<input name="product.name" placeholder="Product Name">
|
|
351
|
+
<input name="product.price" type="number" placeholder="Price">
|
|
352
|
+
|
|
353
|
+
<input name="categories[]" type="checkbox" value="electronics">
|
|
354
|
+
<input name="categories[]" type="checkbox" value="gadgets">
|
|
355
|
+
|
|
356
|
+
<input name="variants[0].size" placeholder="Size">
|
|
357
|
+
<input name="variants[0].color" placeholder="Color">
|
|
358
|
+
<input name="variants[1].size" placeholder="Size">
|
|
359
|
+
<input name="variants[1].color" placeholder="Color">
|
|
360
|
+
|
|
361
|
+
<input name="supplier.company" placeholder="Company">
|
|
362
|
+
<input name="supplier.contact.email" placeholder="Email">
|
|
363
|
+
</form>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
const productData = {
|
|
368
|
+
product: {
|
|
369
|
+
name: 'Wireless Headphones',
|
|
370
|
+
price: 99.99
|
|
371
|
+
},
|
|
372
|
+
categories: ['electronics', 'gadgets'],
|
|
373
|
+
variants: [
|
|
374
|
+
{ size: 'M', color: 'black' },
|
|
375
|
+
{ size: 'L', color: 'white' }
|
|
376
|
+
],
|
|
377
|
+
supplier: {
|
|
378
|
+
company: 'TechCorp',
|
|
379
|
+
contact: {
|
|
380
|
+
email: 'orders@techcorp.com'
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
setFormData(form, productData);
|
|
386
|
+
|
|
387
|
+
// Later, extract the data
|
|
388
|
+
const extractedData = readData(form);
|
|
389
|
+
// Result matches the original structure
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Type Converters
|
|
393
|
+
|
|
394
|
+
### Built-in Converters
|
|
395
|
+
|
|
396
|
+
| Converter | Input | Output |
|
|
397
|
+
|-----------|-------|--------|
|
|
398
|
+
| `BooleanConverter` | `'true'`, `'on'`, `'1'`, any positive number string -> `true`; `'false'`, `'off'`, `'0'` -> `false` | `boolean` |
|
|
399
|
+
| `NumberConverter` | Numeric string | `number` |
|
|
400
|
+
| `DateConverter` | ISO or locale-formatted date string | `Date` |
|
|
401
|
+
|
|
402
|
+
#### Locale-Aware Date Parsing
|
|
403
|
+
|
|
404
|
+
`DateConverter` detects the current locale and parses dates in the local format:
|
|
405
|
+
|
|
406
|
+
| Locale | Format | Example |
|
|
407
|
+
|--------|--------|---------|
|
|
408
|
+
| `en` (US) | `MM/DD/YYYY` | `01/15/2024` |
|
|
409
|
+
| `sv` (Swedish) | `YYYY-MM-DD` | `2024-01-15` |
|
|
410
|
+
| `de` (German) | `DD.MM.YYYY` | `15.01.2024` |
|
|
411
|
+
|
|
412
|
+
ISO format (`2024-01-15`) is always accepted regardless of locale.
|
|
413
|
+
|
|
414
|
+
### Custom Type via `data-type` Attribute
|
|
415
|
+
|
|
416
|
+
Use the `data-type` attribute to override conversion for any field:
|
|
417
|
+
|
|
418
|
+
```html
|
|
419
|
+
<input name="salary" data-type="number" value="50000" />
|
|
420
|
+
<input name="active" data-type="boolean" value="true" />
|
|
421
|
+
<input name="birthday" data-type="Date" value="2000-01-15" />
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
const data = readData(form);
|
|
426
|
+
console.log(data.salary); // number: 50000
|
|
427
|
+
console.log(data.active); // boolean: true
|
|
428
|
+
console.log(data.birthday); // Date object
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Supported `data-type` values: `number`, `boolean`, `string`, `Date`.
|
|
432
|
+
|
|
433
|
+
### Date and Time Handling
|
|
434
|
+
|
|
435
|
+
```html
|
|
436
|
+
<input name="startDate" type="date">
|
|
437
|
+
<input name="startTime" type="time">
|
|
438
|
+
<input name="duration" type="time" step="900"> <!-- 15 min steps -->
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
// Custom handling for combining date and time
|
|
443
|
+
document.querySelector('[name="startTime"]').getData = function() {
|
|
444
|
+
const dateInput = form.querySelector('[name="startDate"]') as HTMLInputElement;
|
|
445
|
+
const timeInput = this as HTMLInputElement;
|
|
446
|
+
|
|
447
|
+
if (dateInput.value && timeInput.value) {
|
|
448
|
+
return new Date(`${dateInput.value}T${timeInput.value}`);
|
|
449
|
+
}
|
|
450
|
+
return null;
|
|
451
|
+
};
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Input Type Conversion Table
|
|
455
|
+
|
|
456
|
+
| Input Type | Converted To |
|
|
457
|
+
|------------|--------------|
|
|
458
|
+
| `checkbox` | `boolean` |
|
|
459
|
+
| `number` | `number` |
|
|
460
|
+
| `date` | `Date` |
|
|
461
|
+
| `datetime-local` | `Date` |
|
|
462
|
+
| `month` | `Date` (first of month) |
|
|
463
|
+
| `week` | `{ year, week }` |
|
|
464
|
+
| `time` | `{ hours, minutes, seconds }` |
|
|
465
|
+
| Default | `string` |
|