@@ -24,6 +24,7 @@ npm install --save-prod roqueform
24
24
- [ Reacting to changes] ( #reacting-to-changes )
25
25
- [ Plugins] ( #plugins )
26
26
- [ Composing plugins] ( #composing-plugins )
27
+ - [ Form submission] ( #form-submission )
27
28
- [ Validation] ( #validation )
28
29
- [ Accessors] ( #accessors )
29
30
@@ -114,12 +115,14 @@ the `dispatchValue` method that updates the field value:
114
115
``` ts
115
116
const field = useField ({ foo: ' bar' });
116
117
117
- field .value // → { foo: 'bar' }
118
+ field .getValue ();
119
+ // → { foo: 'bar' }
118
120
119
121
field .dispatchValue ({ foo: ' qux' });
120
122
121
123
// The field value was updated
122
- field .value // → { foo: 'qux' }
124
+ field .getValue ();
125
+ // → { foo: 'qux' }
123
126
```
124
127
125
128
` useField ` doesn't trigger a re-render of the enclosing component. Navigate to
@@ -131,15 +134,21 @@ When the parent field is updated using `dispatchValue`, all of the affected deri
131
134
const field = useField ({ foo: ' bar' });
132
135
const fooField = field .at (' foo' );
133
136
134
- field .value // → { foo: 'bar' }
135
- fooField .value // → 'bar'
137
+ field .getValue ();
138
+ // → { foo: 'bar' }
139
+
140
+ fooField .getValue ();
141
+ // → 'bar'
136
142
137
143
// Updating the root field
138
144
field .dispatchValue ({ foo: ' qux' });
139
145
140
146
// The update was propagated to the derived field
141
- field .value // → { foo: 'qux' }
142
- fooField .value // → 'qux'
147
+ field .getValue ();
148
+ // → { foo: 'qux' }
149
+
150
+ fooField .getValue ();
151
+ // → 'qux'
143
152
```
144
153
145
154
The same is valid for updating derived fields: when the derived field is updated using ` dispatchValue ` , the update is
@@ -153,8 +162,11 @@ const fooField = field.at('foo');
153
162
fooField .dispatchValue (' qux' );
154
163
155
164
// The update was propagated to the parent field
156
- field .value // → { foo: 'qux' }
157
- fooField .value // → 'qux'
165
+ field .getValue ();
166
+ // → { foo: 'qux' }
167
+
168
+ fooField .getValue ();
169
+ // → 'qux'
158
170
```
159
171
160
172
` dispatchValue ` has a callback signature:
@@ -179,33 +191,41 @@ const fooField = field.at('foo');
179
191
fooField .setValue (' qux' );
180
192
181
193
// 🟡 Notice that fooField was updated but field wasn't
182
- field .value // → { foo: 'bar' }
183
- fooField .value // → 'qux'
194
+ field .getValue ();
195
+ // → { foo: 'bar' }
196
+
197
+ fooField .getValue ();
198
+ // → 'qux'
184
199
185
200
// Notify the parent, "git commit"
186
201
fooField .dispatch ();
187
202
188
203
// Now both fields are in sync
189
- field .value // → { foo: 'qux' }
190
- fooField .value // → 'qux'
204
+ field .getValue ();
205
+ // → { foo: 'qux' }
206
+
207
+ fooField .getValue ();
208
+ // → 'qux'
191
209
```
192
210
193
211
` setValue ` can be called multiple times, but the most recent update would be propagated to the parent only after
194
212
` dispatch ` /` dispatchValue ` call.
195
213
196
- You can check that the field has a transient value using ` transient ` property :
214
+ You can check that the field has a transient value using ` isTransient ` method :
197
215
198
216
``` ts
199
217
const field = useField ({ foo: ' bar' });
200
218
const fooField = field .at (' foo' );
201
219
202
220
fooField .setValue (' qux' );
203
221
204
- fooField .transient // → true
222
+ fooField .isTransient ();
223
+ // → true
205
224
206
225
fooField .dispatch ();
207
226
208
- fooField .transient // → false
227
+ fooField .isTransient ();
228
+ // → false
209
229
```
210
230
211
231
## Field observability
@@ -241,7 +261,7 @@ const App = () => {
241
261
<Field field = { rootField } >
242
262
{ rootField => (
243
263
<input
244
- value = { rootField .value }
264
+ value = { rootField .getValue () }
245
265
onChange = { event => {
246
266
rootField .dispatchValue (event .target .value );
247
267
}}
@@ -267,7 +287,7 @@ const App = () => {
267
287
{ fooField => (
268
288
<input
269
289
type = " text"
270
- value = { fooField .value }
290
+ value = { fooField .getValue () }
271
291
onChange = { event => {
272
292
fooField .dispatchValue (event .target .value );
273
293
}}
@@ -279,7 +299,7 @@ const App = () => {
279
299
{ barField => (
280
300
<input
281
301
type = " number"
282
- value = { barField .value }
302
+ value = { barField .getValue () }
283
303
onChange = { event => {
284
304
barField .dispatchValue (event .target .valueAsNumber );
285
305
}}
@@ -311,14 +331,14 @@ const App = () => {
311
331
312
332
return <>
313
333
<Field field = { rootField } >
314
- { rootField => JSON .stringify (rootField .value )}
334
+ { rootField => JSON .stringify (rootField .getValue () )}
315
335
</Field >
316
336
317
337
<Field field = { rootField .at (' bar' )} >
318
338
{ barField => (
319
339
<input
320
340
type = " text"
321
- value = { barField .value }
341
+ value = { barField .getValue () }
322
342
onChange = { event => {
323
343
barField .dispatchValue (event .target .value );
324
344
}}
@@ -339,7 +359,7 @@ affected.
339
359
+ field={rootField}
340
360
+ eagerlyUpdated={true}
341
361
+ >
342
- {rootField => JSON.stringify(rootField.value )}
362
+ {rootField => JSON.stringify(rootField.getValue() )}
343
363
</Field>
344
364
```
345
365
@@ -360,7 +380,7 @@ is triggered only when the field value was updated [non-transiently](#transient-
360
380
{ barField => (
361
381
<input
362
382
type = " text"
363
- value = { barField .value }
383
+ value = { barField .getValue () }
364
384
onChange = { event => {
365
385
barField .dispatchValue (event .target .value );
366
386
}}
@@ -377,13 +397,13 @@ Let's enhance the field with the `ref` property that would hold the `RefObject`:
377
397
378
398
``` ts
379
399
import { createRef } from ' react' ;
380
- import { useField } from ' roqueform' ;
400
+ import { Plugin , useField } from ' roqueform' ;
381
401
382
- const rootField = useField (
383
- { bar: ' qux' },
402
+ const refPlugin: Plugin <any , { ref: RefObject <HTMLInputElement > }> = field => {
403
+ return { ... field , ref: createRef () };
404
+ };
384
405
385
- field => Object .assign (field , { ref: createRef <HTMLInputElement >() })
386
- );
406
+ const rootField = useField ({ bar: ' qux' }, refPlugin );
387
407
// → Field<{ bar: string }, { ref: RefObject<HTMLInputElement> }> & { ref: RefObject<HTMLInputElement> }
388
408
```
389
409
@@ -397,7 +417,7 @@ itself.
397
417
<input
398
418
// 🟡 Notice the ref property
399
419
ref = { barField .ref }
400
- value = { barField .value }
420
+ value = { barField .getValue () }
401
421
onChange = { event => {
402
422
barField .dispatchValue (event .target .value );
403
423
}}
@@ -434,6 +454,42 @@ import { refPlugin } from '@roqueform/ref-plugin';
434
454
const field = useField ({ bar: ' qux' }, applyPlugins (refPlugin (), anotherPlugin ));
435
455
```
436
456
457
+ # Form submission
458
+
459
+ Without plugins, Roqueform only manages the state of the form fields, and doesn't affect how the form is submitted. So
460
+ you can use ` form ` tags as you did before, but read input values from the ` Field ` object:
461
+
462
+ ``` tsx
463
+ const field = useField ({ foo: ' bar' });
464
+
465
+ const handleSubmit = (event : SyntheticEvent ): void => {
466
+ event .preventDefault ();
467
+
468
+ const value = field .getValue ();
469
+ // Submit the value here
470
+ };
471
+
472
+ <form onSubmit = { handleSubmit } >
473
+ <Field field = { field .at (' bar' )} >
474
+ { barField => (
475
+ <input
476
+ name = " bar"
477
+ value = { barField .getValue ()}
478
+ onChange = { event => {
479
+ barField .dispatchValue (event .target .value );
480
+ }}
481
+ />
482
+ )}
483
+ </Field >
484
+
485
+ <button type = " submit" >
486
+ { ' Submit' }
487
+ </button >
488
+ </form >
489
+ ```
490
+
491
+ You can always [ create a plugin] ( #plugins ) that would enhance the ` Field ` with custom submit mechanics.
492
+
437
493
# Validation
438
494
439
495
Roqueform isn't tied to any validation library. You can use an existing plugin, or write your own plugin to extend
@@ -461,8 +517,8 @@ Plugin enhances all fields with `validate` method that triggers the validation:
461
517
``` ts
462
518
field .validate ();
463
519
464
- field .at (' bar' ).error ?.message
465
- // → " Must have the minimum length of 5"
520
+ field .at (' bar' ).getError () ?.message
521
+ // → ' Must have the minimum length of 5'
466
522
```
467
523
468
524
You can manually set and clear field errors:
@@ -477,10 +533,10 @@ This comes in handy when you receive an error after a backend validation and wan
477
533
field.
478
534
479
535
``` tsx
480
- const handleSubmit = (event ) => {
536
+ const handleSubmit = (event : SyntheticEvent ) => {
481
537
field .validate ();
482
538
483
- if (field .invalid ) {
539
+ if (field .isInvalid () ) {
484
540
event .preventDefault ();
485
541
}
486
542
};
@@ -491,14 +547,14 @@ const handleSubmit = (event) => {
491
547
<>
492
548
<input
493
549
name = " bar"
494
- value = { barField .value }
550
+ value = { barField .getValue () }
495
551
onChange = { event => {
496
552
barField .dispatchValue (event .target .value );
497
553
}}
498
- aria-invalid = { barField .invalid }
554
+ aria-invalid = { barField .isInvalid () }
499
555
/>
500
556
501
- { barField .error ?.message }
557
+ { barField .getError () ?.message }
502
558
</>
503
559
)}
504
560
</Field >
0 commit comments