final-form-formdata v0.1.0-alpha
final-form-formData
A decorator to convert submitted final-form data into formData.
Motivation
final-form stores it's state just as a normal javascript object. This would normally be serialized into JSON before being sent to the backend. However there are a few situations where other formats may be required.
- File uploads require
multi-part/formdata(Filesare not JSON serializable). Whilst it is possible to handle file uploads separately, there are plenty of situations where it is preferable to submit your files and form-data as a single request. - If you are updating your front-end, and your backend is expecting
multi-part/formdatathis allows you to update front-end and back-end independently.
Installation
npm install final-form-formdataBasic Usage
Simply wrap your onSubmit function with convertToFormData and instead of recieving the raw values from final-form, your onSubmit data will recieve a formData instance. e.g.
import {convertToFormData} from "final-form-formdata"
// for final-form
const formDataOnSubmit(onSubmit)
const form = createForm({ onSubmit: formDataOnSubmit })
//for react-final-form
const myForm = () => (
<Form
onSubmit={convertToFormData(onSubmit)}
...
/>
)There is an optional config argument explained further below. When you send the data, make sure you remember to set your content-type request header to "multipart/form-data".
Under the hood
FormData is made up of an entry list where each entry is a key/value pair consisting of only USVStrings or Blobs. All other types are converted. You can have multiple values with the same key (forming an array). Since final-form field values can be equal to anything, this leaves open the problem of how complex data-types are serialised into FormData entries.
final-form-formdata serializes the data according to the following rules:
- All registered fields are added as an entry, where the key is equal to the field name, and the value is the value of the field.
- Primative data-types are just added as is (since they will be converted into a sensible string representation of their value).
- Objects (including arrays) that have a registered sub-field will be ignored, since their children will make up their own entries.
- If a fields value is an array, then each element in the array is added with the same key.
FieldArrays are dealt with in the same fashion. If an elements value is non-primative, rule 5 is applied when adding the entry. - For values not covered by the rules 2-3, we defer to the
handleComplexValuesfunction.
config
config accepts one value, handleComplexValues which deals with non-primative data types.
For example:
const applyFilenames = (fieldName, value, formData, fieldNames) => {
if (typeof value === 'object' && "filename" in value) {
formData.append(fieldName, value.file, value.filename)
}
}
const decoratedOnSubmit = convertToFormData(onSubmit, applyFilenames)
const myForm = () => (
<Form
onSubmit={decoratedOnSubmit}
...
/>
)Two complex value handlers are exported with the library:
appendAll: all values are just added as an entryonlyAcceptBlobs:Blobs (includingFiles) are added, but all other objects are ignored.
The default value is acceptAll, but you can of course write your own.
Testing
Note that this uses the FormData interface, some old testing frameworks may not support this. You can either mock the function, use a polyfill or use a more up to date test runner.
Contributions
Contributions are most welcome :) Please submit a PR or open an issue to discuss
5 years ago