Skip to content

NickMaev/NSerializeJson

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

npm version npm downloads

Description

NSerializeJson is a Vanilla JS form serializer which serializes form data into JSON object.

Changes

v. 1.0.3 (2019-08-13)
  • Dot separator parsing fix.
  • Added more examples.
v. 1.0.2 (2018-11-11)

select element parsing fix.

Usage

Install

npm install nserializejson

Prepare and usage

Import:

import {NSerializeJson} from "nserializejson";

or use the scripts tag (bundle):

<script src="nserializejson.min.js"></script>

Define the HTML form:

<form id="myForm">
  <input type="text" name="title" value="Finding Loot"/>
  <input type="text" name="author[name]" value="John Smith"/>
  <input type="text" name="author[job]"  value="Legendary Pirate"/>
</form>

Then: (TypeScript)

NSerializeJson.serializeForm(document.getElementById("myForm") as HTMLFormElement);

(JavaScript, using scripts tag)

NSerializeJson.NSerializeJson.serializeForm(document.getElementById("myForm")); // In JS bundle NSerializeJson.* required, because of UMD library!

Returns:

{
  title: "Finding Loot",
  author: {
    name: "John Smith",
    job: "Legendary Pirate"
  }
}

Form input, textarea and select tags are supported. Nested attributes and arrays can be specified by using the attr[nested][nested] syntax.

HTML form:

<form id="my-profile">
  <!-- simple attribute -->
  <input type="text" name="fullName"              value="Nikolay Maev" />

  <!-- nested attributes -->
  <input type="text" name="address[city]"         value="Rostov-on-Don" />
  <input type="text" name="address[state][name]"  value="Rostov oblast'" />
  <input type="text" name="address[state][abbr]"  value="ROV" />

  <!-- array -->
  <input type="text" name="jobbies[]"             value="coding" />
  <input type="text" name="jobbies[]"             value="cycling" />

  <!-- nested arrays, textareas, checkboxes ... -->
  <textarea              name="projects[0][name]">NVal</textarea>
  <textarea              name="projects[0][language]">TypeScript</textarea>
  <input type="hidden"   name="projects[0][popular]" value="0" />
  <input type="checkbox" name="projects[0][popular]" value="1" checked />

  <textarea              name="projects[1][name]">NSerializeJson</textarea>
  <textarea              name="projects[1][language]">TypeScript</textarea>
  <input type="hidden"   name="projects[1][popular]" value="0" />
  <input type="checkbox" name="projects[1][popular]" value="1"/>

  <!-- select -->
  <select name="selectOne">
    <option value="paper">Paper</option>
    <option value="rock" selected>Rock</option>
    <option value="scissors">Scissors</option>
  </select>

  <!-- select multiple options, just name it as an array[] -->
  <select multiple name="selectMultiple[]">
    <option value="red"  selected>Red</option>
    <option value="blue" selected>Blue</option>
    <option value="yellow">Yellow</option>
	</select>
</form>

HTML form (dot separator):

<form id="my-profile">
  <!-- simple attribute -->
  <input type="text" name="fullName"              value="Nikolay Maev" />

  <!-- nested attributes -->
  <input type="text" name="address.city"         value="Rostov-on-Don" />
  <input type="text" name="address.state.name"  value="Rostov oblast'" />
  <input type="text" name="address.state.abbr"  value="ROV" />

  <!-- array -->
  <input type="text" name="jobbies[]"             value="coding" />
  <input type="text" name="jobbies[]"             value="cycling" />

  <!-- nested arrays, textareas, checkboxes ... -->
  <textarea              name="projects[0].name">NVal</textarea>
  <textarea              name="projects[0].language">TypeScript</textarea>
  <input type="hidden"   name="projects[0].popular" value="0" />
  <input type="checkbox" name="projects[0].popular" value="1" checked />

  <textarea              name="projects[1].name.">NSerializeJson</textarea>
  <textarea              name="projects[1].language">TypeScript</textarea>
  <input type="hidden"   name="projects[1].popular" value="0" />
  <input type="checkbox" name="projects[1].popular" value="1"/>

  <!-- select -->
  <select name="selectOne">
    <option value="paper">Paper</option>
    <option value="rock" selected>Rock</option>
    <option value="scissors">Scissors</option>
  </select>

  <!-- select multiple options, just name it as an array[] -->
  <select multiple name="selectMultiple[]">
    <option value="red"  selected>Red</option>
    <option value="blue" selected>Blue</option>
    <option value="yellow">Yellow</option>
	</select>
</form>

JavaScript:

NSerializeJson.serializeForm(document.getElementById("my-profile") as HTMLFormElement)

// returns =>
{
  fullName: "Nikolay Maev",

  address: {
    city: "Rostov-on-Don",
    state: {
      name: "Rostov oblast'",
      abbr: "ROV"
    }
  },

  jobbies: ["coding", "cycling"],

  projects: {
    '0': { name: "NVal", language: "TypeScript", popular: "1" },
    '1': { name: "NSerializeJson",   language: "TypeScript", popular: "0" }
  },

  selectOne: "rock",
  selectMultiple: ["red", "blue"]
}

The serializeForm function returns a JavaScript object, not a JSON String.

Parse values with :types

All attribute values are auto by default. But you can force values to be parsed with specific types by appending the type with a colon.

<form id="myForm">
  <input type="text" name="strbydefault"     value=":string is the default (implicit) type"/>
  <input type="text" name="text:string"      value=":string type can still be used to override other parsing options"/>
  <input type="text" name="excluded:skip"    value="Use :skip to not include this field in the result"/>

  <input type="text" name="numbers[0]:number"           value="0"/>
  <input type="text" name="numbers[1]:number"           value="1"/>
  
  <input type="text" name="keys[1.1]:number"         value="1.1"/>

  <input type="text" name="bools[true]:boolean"      value="true"/>
  <input type="text" name="bools[false]:boolean"     value="false"/>
  <input type="text" name="bools[zero]:boolean"         value="0"/>

  <input type="text" name="autos[string]:auto"          value="text with stuff"/>
  <input type="text" name="autos[one]:auto"               value="1"/>
  <input type="text" name="autos[two]:auto"               value="2"/>
  <input type="text" name="autos[true]:auto"            value="true"/>
  <input type="text" name="autos[false]:auto"           value="false"/>
  <input type="text" name="autos[null]:auto"            value="null"/>
  <input type="text" name="autos[list]:auto"            value='1, 2, 3, foo, bar, {"pet": "cat"}'/>
  
  <input type="text" name="arrays[empty]:array[auto]"        value=""/>
  <input type="text" name="arrays[auto]:array[auto]"         value="1, 2, 3, foo, bar"/>
  <input type="text" name="arrays[numbers]:array[number]"     value="1, 2, 3, foo, bar"/>

  <input type="text" name="json[empty]:json"       value="{}"/>
  <input type="text" name="json[not empty]:json"   value='{"my": "stuff"}'/>
</form>
NSerializeJson.serializeForm(document.getElementById("myForm") as HTMLFormElement);

// returns =>
{
	"strbydefault": ":string is the default (implicit) type",
	"text": ":string type can still be used to override other parsing options",
	"numbers": [
		0,
		1
	],
	"keys": {
		"1.1": 1.1
	},
	"bools": {
		"true": true,
		"false": false,
		"zero": false
	},
	"autos": {
		"string": "text with stuff",
		"one": 1,
		"two": 2,
		"true": true,
		"false": false,
		"null": null,
		"list": [
			1,
			2,
			3,
			"foo",
			"bar",
			{
				"pet": "cat"
			}
		]
	},
	"arrays": {
		"empty": [],
		"auto": [
			1,
			2,
			3,
			"foo",
			"bar"
		],
		"numbers": [
			1,
			2,
			3,
			null, // <-- Non-digit.
			null // <-- Non-digit.
		]
	},
	"json": {
		"empty": {},
		"not empty": {
			"my": "stuff"
		}
	}
}

Types can also be specified with the attribute data-value-type, instead of having to add the ":type" suffix:

<form>
  <input type="text" name="anumb"   data-value-type="number"  value="1"/>
  <input type="text" name="abool"   data-value-type="boolean" value="true"/>
  <input type="text" name="astring" data-value-type="string"  value="0"/>
</form>

Options

By default .serializeForm() with default options has this behavior:

  • Values are always auto (unless appending :types to the input names)
  • Unchecked checkboxes are ignored (as defined in the W3C rules for successful controls).
  • Disabled elements are ignored (W3C rules)
  • String keys are always string except the numbers

Allowed options NSerializeJson.options to change the default behavior:

  • forceNullOnEmpty: false, if true, will record null instead of empty value. Otherwise, records empties ("", 0, false).
  • useDotSeparatorInPath: false, if true allows you to use the dot notation instead of brackets in the name attribute (i.e. <input name="food.fruits[]" value="banana">).
  • useNumKeysAsArrayIndex: true, when using integers as keys (i.e. <input name="foods[0]" value="banana">), serialize as an array ({"foods": ["banana"]}) instead of an object ({"foods": {"0": "banana"}).
  • onBeforeParseValue: null, if not null, allows you to prepare the value and return it by this method with signature (value: string, type: string) => string;.

Also you may parametrize the serialization method: .serializeForm(htmlFormElement, options, parsers).

More info about options usage in the sections below.

Custom Types

You can define your own types or override the defaults with the customTypes option. For example:

<form id="myForm">
  <input type="text" name="scary:alwaysBoo" value="not boo"/>
  <input type="text" name="str:string"      value="str"/>
  <input type="text" name="number:number"   value="5"/>
</form>
NSerializeJson.parsers.push([
	{
        name: "alwaysBoo",
        parse: (val: any, forceNull: boolean): any => {
			return "boo";
        }
    }
]);

var stringParser = NSerializeJson.parsers.filter(x => x.name === "string")[0];
stringParser.parse = (val: any, forceNull: boolean): any => {
	return val + " override";
}

NSerializeJson.serializeForm(document.getElementById("myForm") as HTMLFormElement);

// returns =>
{
  "scary": "boo",        // <-- parsed with type :alwaysBoo
  "str": "str override", // <-- parsed with new type :string (instead of the default)
  "number": 5,           // <-- the default :number still works
}

The default parsers are defined in NSerializeJson.parsers. If you want to define your own set of parsers, you could also re-define that object.

Use integer keys as array indexes

By default, all serialized integer numbers are indices, so if you want to serialize it as string keys you have to set the useNumKeysAsArrayIndex: false:

<form id="myForm">
  <input type="text" name="arr[0]" value="foo"/>
  <input type="text" name="arr[1]" value="var"/>
  <input type="text" name="arr[5]" value="inn"/>
</form>
NSerializeJson.options.useNumKeysAsArrayIndex = false;
NSerializeJson.serializeForm(document.getElementById("myForm") as HTMLFormElement);
// arr is an object =>
{'arr': {'0': 'foo', '1': 'var', '5': 'inn' }}

NSerializeJson.options.useNumKeysAsArrayIndex = true;
NSerializeJson.serializeForm(document.getElementById("myForm") as HTMLFormElement);
// arr is an array =>
{'arr': ['foo', 'var', null, null, null, 'inn']}