- Collect and parse form values in one line
- Parse values based on field type (ex:
type="number"
) or data-type (ex:data-type="boolean"
) - Use custom parser with
data-type
- Build arrays and objects based on field name
- Trim and nullify values
- Filter values using a custom function
- Clean values using a custom function
- Framework-agnostic
- TypeScript declarations ♥
Play with the lib here: https://codesandbox.io/s/jalik-form-parser-demo-r29grh?file=/src/index.js
npm i -P @jalik/form-parser
yarn add @jalik/form-parser
Let's start with the form below :
<form id="my-form">
<input name="username" value="jalik">
<input name="password" value="secret">
<input name="age" type="number" value="35">
<input name="gender" type="radio" value="male" checked>
<input name="gender" type="radio" value="female">
<input name="email" type="email" value="[email protected]">
<input name="phone" type="tel" data-type="string" value="067123456">
<input name="subscribe" type="checkbox" data-type="boolean" value="true" checked>
<input name="token" type="hidden" value="aZ7hYkl12mPx">
<button type="submit">Submit</button>
</form>
You can collect and parse fields with parseForm(form, options)
.
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
// Parse form values with default options
const fields = parseForm(form)
The fields
object will look like this :
{
"username": "jalik",
"password": "secret",
"age": 35,
"gender": "male",
"email": "[email protected]",
"phone": "067123456",
"subscribe": true,
"token": "aZ7hYkl12mPx"
}
Below is a more complete form example, with a lot of different cases to help you understand the behavior of the parsing function (pay attention to comments, values and attributes).
<form id="my-form">
<!-- Fields without name are ignored -->
<input type="text" value="aaa">
<!-- Disabled fields are always ignored -->
<input name="disabled_field" value="hello" disabled>
<!-- Buttons are always ignored -->
<input name="input_button" type="button" value="Click me">
<input name="input_reset" type="reset" value="Reset">
<input name="input_submit" type="submit" value="Submit">
<button name="button" type="button" value="Click me"></button>
<button name="reset" type="reset" value="Reset"></button>
<button name="submit" type="submit" value="Submit"></button>
<!-- These fields will be parsed to booleans -->
<!-- boolean = false -->
<input name="boolean" type="radio" data-type="boolean" value="true">
<input name="boolean" type="radio" data-type="boolean" value="false" checked>
<!-- hidden_boolean = true -->
<input name="hidden_boolean" type="hidden" data-type="auto" value="true">
<!-- These fields will be parsed to numbers -->
<!-- hidden_float = 9.99 -->
<input name="hidden_float" type="hidden" data-type="number" value="09.99">
<!-- text_integer = 1 -->
<input name="text_integer" type="text" data-type="number" value="01">
<!-- select_number = 30 -->
<select name="select_number" data-type="number">
<option>10</option>
<option>20</option>
<option selected>30</option>
</select>
<!-- float = 9.99 -->
<input name="float" type="number" value="09.99">
<!-- integer = 1 -->
<input name="integer" type="number" value="01">
<!-- range = 0118 -->
<input name="range" type="range" value="0118">
<!-- These fields will be parsed to strings -->
<!-- number_text = '0123' -->
<input name="number_text" type="number" data-type="string" value="0123">
<!-- date = '2017-11-14' -->
<input name="date" type="date" value="2017-11-14">
<!-- file = 'file://path/to/file.txt' -->
<input name="file" type="file" value="file://path/to/file.txt">
<!-- hidden_text = 'shadowed' -->
<input name="hidden_text" type="hidden" value="shadowed">
<!-- month = '2017-11' -->
<input name="month" type="month" value="2017-11">
<!-- text = 'Hello' -->
<input name="text" type="text" value="Hello">
<!-- url = 'http://www.github.com/' -->
<input name="url" type="url" value="http://www.github.com/">
<!-- week = '2017-W16' -->
<input name="week" type="week" value="2017-W16">
<!-- textarea = 'Hello' -->
<textarea name="textarea">Hello</textarea>
<!-- Passwords are never altered or parsed ("data-type" is ignored) -->
<!-- password = ' 1337 ' -->
<input name="password" type="password" data-type="number" value=" 1337 ">
<!-- These fields will be parsed as array -->
<!-- select_multiple = [20, 30] -->
<select name="select_multiple" data-type="number" multiple>
<option>10</option>
<option selected>20</option>
<option selected>30</option>
</select>
<!-- array = ['A', 'B'] -->
<input name="array[]" type="checkbox" value="A" checked>
<input name="array[]" type="checkbox" value="B" checked>
</form>
To get form fields :
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
// Parse form values using default options
const fields = parseForm(form)
The fields
object will look like this :
{
"boolean": false,
"hidden_boolean": true,
"float": 9.99,
"hidden_float": 9.99,
"text_integer": 1,
"integer": 1,
"range": 118,
"select_number": 30,
"date": "2017-11-14",
"file": "file://path/to/file.txt",
"hidden_text": "shadowed",
"month": "2017-11",
"number_text": "0123",
"text": "Hello",
"url": "http://www.github.com/",
"textarea": "Hello",
"password": " 1337 ",
"array": [
"A",
"B"
],
"select_multiple": [
20,
30
]
}
To get an array of values, append []
to a field name:
<form id="my-form">
<!-- This will create an array with checked values -->
<input name="array[]" type="checkbox" value="A">
<input name="array[]" type="checkbox" value="B" checked>
<input name="array[]" type="checkbox" value="C" checked>
<!-- This will create an array with checked values (indexed) -->
<input name="colors[2]" type="checkbox" value="red" checked>
<input name="colors[1]" type="checkbox" value="blue">
<input name="colors[0]" type="checkbox" value="white" checked>
</form>
Get fields values :
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
// Parse form values using default options
const fields = parseForm(form)
The fields
object will look like this :
{
"array": [
"B",
"C"
],
"colors": [
"white",
undefined,
"red"
]
}
To get an object, write attributes like [attribute]
:
<form id="my-form">
<!-- This will create an object with those attributes -->
<input name="address[street]" value="Av. Pouvanaa a Oopa">
<input name="address[city]" value="Papeete">
</form>
Get fields values :
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
// Parse form values using default options
const fields = parseForm(form)
The fields
object will look like this :
{
"address": {
"street": "Av. Pouvanaa a Oopa",
"city": "Papeete"
}
}
If you need to create an object with numbers as attributes, use single or double quotes to force the parser to interpret it as a string and then creating an object instead of an array.
<form id="my-form">
<!-- This will create an object with those attributes -->
<input name="elements['0']" value="Zero">
<input name="elements['1']" value="One">
<input name="elements['2']" value="Two">
</form>
Will give this :
{
"elements": {
"0": "Zero",
"1": "One",
"2": "Two"
}
}
Instead of :
{
"elements": [
"Zero",
"One",
"Two"
]
}
To define the type of field, you can use the attribute data-type
or type
.
The attribute data-type
takes precedence over type
if both of are defined.
When using data-type
attribute, the value can be:
auto
to convert the value to the best guess type (ex:123
=>number
,true
=>boolean
)boolean
to convert the value to a boolean (ex:true
,1
,yes
,on
,false
,0
,no
,off
)number
to convert the value to a number
When using type
attribute on <input>
, only number
and range
are parsed to numbers.
<!-- This will parse "true" as a boolean -->
<input name="boolean" type="text" data-type="boolean" value="true">
<!-- This will parse "01" as a number -->
<input name="integer" type="text" data-type="number" value="01">
<!-- This will parse "09.99" as a number -->
<input name="float" type="text" data-type="number" value="09.99">
<!-- This will parse "0963" as a string -->
<input name="string" type="text" data-type="string" value="0963">
<!-- This will parse "13.37" as a number -->
<input name="anything" type="text" data-type="auto" value="13.37">
<!-- This will parse "false" as a boolean -->
<input name="anything_2" type="text" data-type="auto" value="false">
You may want to create your own data-type
, it is possible since the v3.1.0
by passing the parser
option to parseForm()
or parseField()
.
<form id="my-form">
<input name="phone" data-type="phone" value="689.12345678" />
</form>
import { parseForm } from '@jalik/form-parser'
const form = document.getElementById('my-form')
const fields = parseForm(form, {
parser: (value, dataType, field) => {
if (dataType === 'phone') {
const [code, number] = value.split(/\./)
return {
code,
number,
}
}
return null
},
})
{
"phone": {
"code": "689",
"number": "12345678"
}
}
It is possible to reconstruct an object corresponding to the form structure, so it can parse complex forms containing nested arrays and objects.
<form id="my-form">
<input name="phones[0][code]" type="number" data-type="string" value="689">
<input name="phones[0][number]" type="number" data-type="string" value="87218910">
<input name="phones[1][code]" type="number" data-type="string" value="689">
<input name="phones[1][number]" type="number" data-type="string" value="87218910">
<!-- A useless deep nested field value -->
<input name="deep_1[][deep_2][0][][deep_3]" value="DEEP">
</form>
To get fields :
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
// Parse form values using default options
const fields = parseForm(form)
The fields
object will look like this :
{
"phones": [
{
"code": "689",
"number": "87218910"
},
{
"code": "689",
"number": "87218910"
}
],
"deep_1": [
{
"deep_2": [
[
{
"deep_3": "DEEP"
}
]
]
}
]
}
When parsing a form, you can filter values with filterFunction(field, parsedValue)
option in the parseForm(form, options)
.
The filter function must return true
to return the field.
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
const fields = parseForm(form, {
// returns only text fields
filterFunction: (field, parsedValue) => field.type === 'text'
});
Values can be cleaned by passing cleanFunction(value, field)
to parseForm(form, options)
.
Note that only strings are passed to this function and that password fields are ignored.
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
// Parse form values using default options
const fields = parseForm(form, {
cleanFunction: (value, field) => {
// Apply uppercase to lastName field
if (field.name === 'lastName' || /name/gi.test(field.name)) {
value = value.toUpperCase()
}
// Remove HTML code from all fields
return value.replace(/<\/?[^>]+>/gm, '')
}
})
To parse a single field.
<form>
<select data-type="number" name="values" multiple>
<option>1</option>
<option selected>2</option>
<option selected>3</option>
</select>
</form>
import { parseField } from '@jalik/form-parser'
const field = document.getElementById('values')
const values = parseField(field)
// values = [2, 3]
To parse a form with all fields.
<form id="my-form">
<input type="number" name="age" value="35" />
<select data-type="number" name="values" multiple>
<option>1</option>
<option selected>2</option>
<option selected>3</option>
</select>
</form>
import { parseForm } from '@jalik/form-parser'
// Get an existing HTML form element
const form = document.getElementById('my-form')
const fields = parseForm(form, {
// Cleans parsed values
cleanFunction(value, field) {
return typeof value === 'string' ? stripTags(value) : value
},
// Only returns fields that matches the condition
filterFunction(field) {
return field.type === 'text'
},
// Replace empty strings with null
nullify: true,
// Set parsing mode.
// - none: disable parsing
// - type: enable parsing based on "type" attribute (ex: type="number")
// - data-type: enable parsing based on "data-type" attribute (ex: data-type="number")
// - auto: enable parsing based on data-type and type (in this order)
parsing: 'none' | 'type' | 'data-type' | 'auto',
// Remove extra spaces
trim: true
})
History of releases is in the changelog.
The code is released under the MIT License.