In Search of a Reimplementation of FormData
This is a chat of mine with GitHub Copilot. Nice job GitHub!
movahhedi: Explain line by line exactly what each line of the code from the jquery source code defining the serialize functions for forms does:
jQuery.fn.extend( {
serialize: function() {
return jQuery.param( this.serializeArray() );
},
serializeArray: function() {
return this.map( function() {
// Can add propHook for "elements" to filter or add form elements
var elements = jQuery.prop( this, "elements" );
return elements ? jQuery.makeArray( elements ) : this;
} ).filter( function() {
var type = this.type;
// Use .is( ":disabled" ) so that fieldset[disabled] works
return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !rcheckableType.test( type ) );
} ).map( function( _i, elem ) {
var val = jQuery( this ).val();
if ( val == null ) {
return null;
}
if ( Array.isArray( val ) ) {
return jQuery.map( val, function( val ) {
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
} );
}
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
} ).get();
}
} );
GitHub Copilot: This code is defining two functions, serialize
and serializeArray
, as methods on jQuery objects. Here's a line-by-line breakdown:
jQuery.fn.extend( {
This line is extending the jQuery prototype (also accessible as jQuery.fn
), which means adding new methods to it that will be available on all jQuery objects.
serialize: function() {
return jQuery.param( this.serializeArray() );
},
The serialize
method is defined here. It calls this.serializeArray()
to get an array representation of the form data, and then passes that array to jQuery.param
to convert it into a URL-encoded string.
serializeArray: function() {
The serializeArray
method is defined here. It returns an array representation of the form data.
return this.map( function() {
This line starts a map
operation on the jQuery object (which represents a set of DOM elements). For each element, the provided function is called.
var elements = jQuery.prop( this, "elements" );
return elements ? jQuery.makeArray( elements ) : this;
This code gets the "elements" property of the current DOM element (which should be a form), converts it to a true array if it exists, and returns it. If the "elements" property doesn't exist, it returns the original DOM element.
} ).filter( function() {
This line starts a filter
operation on the result of the map
. For each element, the provided function is called, and if it returns true
, the element is included in the final result.
var type = this.type;
return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !rcheckableType.test( type ) );
This code checks several conditions to determine whether the current form element should be included in the serialized data. It must have a name
, not be disabled, be a submittable type of element, not be a submitter type of element, and either be checked or not be a checkable type of element.
} ).map( function( _i, elem ) {
This line starts another map
operation on the result of the filter
. For each element, the provided function is called.
var val = jQuery( this ).val();
if ( val == null ) {
return null;
}
This code gets the value of the current form element. If the value is null
, it returns null
.
if ( Array.isArray( val ) ) {
return jQuery.map( val, function( val ) {
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
} );
}
If the value is an array (which it will be for multi-selects and checkboxes), it maps each item in the array to an object with name
and value
properties. The value is also replaced any CRLF pairs with a single newline character.
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
If the value is not an array, it returns an object with name
and value
properties. The value is also replaced any CRLF pairs with a single newline character.
} ).get();
This line calls get
on the result of the map
to convert it from a jQuery object back into a true array.
}
} );
These lines close the serializeArray
function, the object passed to jQuery.fn.extend
, and the call to jQuery.fn.extend
, respectively.
movahhedi: explain the following lines fully and extensively and bring the references from the jquery cource code:
// Use .is( ":disabled" ) so that fieldset[disabled] works
return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !rcheckableType.test( type ) );
`
GitHub Copilot: This line of code is part of the filter
function in the serializeArray
method. It's used to determine which form elements should be included in the serialized data. Let's break it down:
return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !rcheckableType.test( type ) );
this.name
: This checks if the current form element has aname
attribute. In HTML forms, thename
attribute is used to identify the form data for each input element when the data is submitted. If an element doesn't have aname
, it won't be included in the serialized data.!jQuery( this ).is( ":disabled" )
: This checks if the current form element is not disabled. The:disabled
selector in jQuery matches all elements that are disabled. So,jQuery( this ).is( ":disabled" )
will returntrue
if the element is disabled, andfalse
otherwise. The!
operator negates this, so the overall condition istrue
if the element is not disabled.rsubmittable.test( this.nodeName )
: This checks if the current form element's node name matches thersubmittable
regular expression. In the jQuery source code,rsubmittable
is defined as/^(?:input|select|textarea|keygen)/i
, which matchesinput
,select
,textarea
, andkeygen
elements. Thei
flag makes the match case-insensitive.!rsubmitterTypes.test( type )
: This checks if the current form element's type does not match thersubmitterTypes
regular expression. In the jQuery source code,rsubmitterTypes
is defined as/^submit|button|image|reset|file$/i
, which matchessubmit
,button
,image
,reset
, andfile
types. Thei
flag makes the match case-insensitive.this.checked || !rcheckableType.test( type )
: This checks if the current form element is checked or if its type does not match thercheckableType
regular expression. In the jQuery source code,rcheckableType
is defined as/^(?:checkbox|radio)$/i
, which matchescheckbox
andradio
types. Thei
flag makes the match case-insensitive. This condition ensures that unchecked checkboxes and radio buttons are not included in the serialized data.
So, overall, this line of code is checking that the current form element has a name
, is not disabled, is an input
, select
, textarea
, or keygen
element, is not a submit
, button
, image
, reset
, or file
type, and is either checked or not a checkbox
or radio
type. If all these conditions are met, the element will be included in the serialized data.
movahhedi: compare this serializeArray function with the FormData Constructor extensively. compare each of the elements` values when used with each. which one supports elements with duplicate names? how does it handle them?
GitHub Copilot: The serializeArray
function in jQuery and the FormData
constructor in vanilla JavaScript are both used to create a set of key/value pairs representing form fields and their values. However, they handle data differently and have different features.
Data Format:
serializeArray
: Returns an array of objects where each object has aname
andvalue
property. For example:[{name: 'username', value: 'John'}, {name: 'password', value: '1234'}]
.FormData
: Returns aFormData
object. You can use theentries
,keys
,values
, orgetAll
methods to retrieve the data. Theentries
method, for example, returns an iterator allowing you to loop through all key/value pairs.
File Inputs:
serializeArray
: Does not support file inputs. If a form containsinput[type=file]
, the file input will not be included in the serialized data.FormData
: Supports file inputs. If a form containsinput[type=file]
, the file input will be included in theFormData
object.
Disabled Inputs:
serializeArray
: Does not include disabled inputs in the serialized data.FormData
: Includes disabled inputs in theFormData
object.
Handling Elements with Duplicate Names:
serializeArray
: Supports elements with duplicate names. If a form contains multiple elements with the same name,serializeArray
will include all of them in the serialized data.FormData
: Also supports elements with duplicate names. If a form contains multiple elements with the same name,FormData
will include all of them. You can use thegetAll(name)
method to retrieve all values with the same name.
Handling Checkbox and Radio Inputs:
serializeArray
: Only includes checkboxes and radio buttons that are checked.FormData
: Also only includes checkboxes and radio buttons that are checked.
Handling Select-multiple Inputs:
serializeArray
: If a select-multiple input has multiple options selected,serializeArray
will include an object for each selected option in the serialized data.FormData
: If a select-multiple input has multiple options selected,FormData
will include a key/value pair for each selected option.
In conclusion, while serializeArray
and FormData
have some similarities, FormData
provides more features and flexibility, especially when dealing with file inputs and disabled inputs. However, the choice between the two often depends on the specific requirements of your project.
movahhedi: how exactly do each handle arrays?
GitHub Copilot: Both serializeArray
and FormData
handle arrays differently, especially when it comes to form elements like multiple select and checkboxes.
serializeArray:
- If a form contains a multiple select box or checkboxes with the same name,
serializeArray
will create an object for each selected option or checked box. Each object will have the samename
(the name of the select box or checkboxes) and avalue
corresponding to the value of the selected option or checked box. - For example, if a form contains a multiple select box named
colors
with optionsred
,blue
, andgreen
selected,serializeArray
will return:[{name: 'colors', value: 'red'}, {name: 'colors', value: 'blue'}, {name: 'colors', value: 'green'}]
.
- If a form contains a multiple select box or checkboxes with the same name,
FormData:
FormData
also supports multiple values for the same name. If a form contains a multiple select box or checkboxes with the same name,FormData
will include a key/value pair for each selected option or checked box.- However, unlike
serializeArray
,FormData
does not return an array directly. You can use thegetAll(name)
method to retrieve all values with the same name as an array. For example, if a form contains a multiple select box namedcolors
with optionsred
,blue
, andgreen
selected,formData.getAll('colors')
will return:['red', 'blue', 'green']
.
In conclusion, while both serializeArray
and FormData
support multiple values for the same name, they represent these values differently. serializeArray
includes them in the main array it returns, while FormData
stores them internally and you need to use the getAll
method to retrieve them as an array.
Subscribe to my newsletter
Read articles from Shahab Movahhedi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Shahab Movahhedi
Shahab Movahhedi
Senior Developer, Designer, Technologist! ๐ฎ๐ท