# 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:
```js
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:

```js
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.

```js
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.

```js
serializeArray: function() {
```
The `serializeArray` method is defined here. It returns an array representation of the form data.

```js
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.

```js
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.

```js
} ).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.

```js
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.

```js
} ).map( function( _i, elem ) {
```
This line starts another `map` operation on the result of the `filter`. For each element, the provided function is called.

```js
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`.

```js
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.

```js
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.

```js
} ).get();
```
This line calls `get` on the result of the `map` to convert it from a jQuery object back into a true array.

```js
}
} );
```
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:
```js
            // 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:

```js
return this.name && !jQuery( this ).is( ":disabled" ) &&
    rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
    ( this.checked || !rcheckableType.test( type ) );
```

1. `this.name`: This checks if the current form element has a `name` attribute. In HTML forms, the `name` attribute is used to identify the form data for each input element when the data is submitted. If an element doesn't have a `name`, it won't be included in the serialized data.

2. `!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 return `true` if the element is disabled, and `false` otherwise. The `!` operator negates this, so the overall condition is `true` if the element is not disabled.

3. `rsubmittable.test( this.nodeName )`: This checks if the current form element's node name matches the `rsubmittable` regular expression. In the jQuery source code, `rsubmittable` is defined as `/^(?:input|select|textarea|keygen)/i`, which matches `input`, `select`, `textarea`, and `keygen` elements. The `i` flag makes the match case-insensitive.

4. `!rsubmitterTypes.test( type )`: This checks if the current form element's type does not match the `rsubmitterTypes` regular expression. In the jQuery source code, `rsubmitterTypes` is defined as `/^submit|button|image|reset|file$/i`, which matches `submit`, `button`, `image`, `reset`, and `file` types. The `i` flag makes the match case-insensitive.

5. `this.checked || !rcheckableType.test( type )`: This checks if the current form element is checked or if its type does not match the `rcheckableType` regular expression. In the jQuery source code, `rcheckableType` is defined as `/^(?:checkbox|radio)$/i`, which matches `checkbox` and `radio` types. The `i` 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.

1. **Data Format:**
   - `serializeArray`: Returns an array of objects where each object has a `name` and `value` property. For example: `[{name: 'username', value: 'John'}, {name: 'password', value: '1234'}]`.
   - `FormData`: Returns a `FormData` object. You can use the `entries`, `keys`, `values`, or `getAll` methods to retrieve the data. The `entries` method, for example, returns an iterator allowing you to loop through all key/value pairs.

2. **File Inputs:**
   - `serializeArray`: Does not support file inputs. If a form contains `input[type=file]`, the file input will not be included in the serialized data.
   - `FormData`: Supports file inputs. If a form contains `input[type=file]`, the file input will be included in the `FormData` object.

3. **Disabled Inputs:**
   - `serializeArray`: Does not include disabled inputs in the serialized data.
   - `FormData`: Includes disabled inputs in the `FormData` object.

4. **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 the `getAll(name)` method to retrieve all values with the same name.

5. **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.

6. **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.

1. **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 same `name` (the name of the select box or checkboxes) and a `value` corresponding to the value of the selected option or checked box.
   - For example, if a form contains a multiple select box named `colors` with options `red`, `blue`, and `green` selected, `serializeArray` will return: `[{name: 'colors', value: 'red'}, {name: 'colors', value: 'blue'}, {name: 'colors', value: 'green'}]`.

2. **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 the `getAll(name)` method to retrieve all values with the same name as an array. For example, if a form contains a multiple select box named `colors` with options `red`, `blue`, and `green` 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.
