Handling Form Submissions
Tags: beginners, javascript, functional
Published: 2020-10-31 14:49:10

# Overview

We will write a 'pure function' that can be used to handle form submissions for _any semantically written_ HTML-CSS form ✨. We will utilize:

1. 'One Line' Fat Arrow Functions
2. Object Destructuring
3. `filter`
4. `reduce`

The end result 🥅 will be that upon a user clicking 'submit,' we will dynamically collect all of the form values, pair them with the corresponding input and wrap it all up into an _object._ 

So, we're going for something like this:

```javascript
{
  name: "Mark Galloway",
  // ... other values from the form paired with 'input ids'.
}
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vfqw0uyskfmnah6xjrqu.gif)

This could just be `log`ged, as we do here, or sent to a server, whatever. The point 📝 is that we will have a _pure function_ that we can use across any/all similar applications.

# Listening 👂🏽 For Form Submissions

As per: `<script src="./scripts.js"></script>`, let's open up 'scripts.js' and start with the following steps:

1. Use the Document Object Model (DOM) to 'query' for the `form`.
2. Listen 👂🏽 for a `"submit"` _event._
3. Prevent the browser from doing its 'default behavior' of submitting to a back-end server (which doesn't exit here).

Here's the code to cover all of those steps 👆🏽.

```js
document.querySelector('form').addEventListener('submit', event => {
  event.preventDefault();
})
```

This line: `addEventListener("submit", (event) => {` is using a _callback function_ written in _ES2015/ES6 'fat arrow'/'lamda' syntax._ For more information:

{% link https://dev.to/codefinity/functions-3a86 %}

That _parameter,_ `event` is bound to the actual 'submission event' that occurs in the browser.

We are also _chaining_ ⛓️ each step together with `.`s as we move along.

Try doing `console.log(event)` right below the `preventDefault()`. You will see that it's nothing but another JS object. This is the result of the DOM API provided by the browser - it conveniently models most of the things as JS objects b/c that's all that JS really understands.

## `event.target.elements`

Inside of the _callback function,_ right underneath: `event.preventDefault()`, do: `console.log(event.target)` 👈🏽 Again, the 'submission event' is modeled as an _object,_ `event.` Currently, we are accessing a 🔑, `target` which will provide as an 'object model' of whatever _Element_ 'triggered' this submission event - i.e. the `form` itself.

Now, fill out the form and check your 'dev tools console.'

![Logging form elements after submission](https://dev-to-uploads.s3.amazonaws.com/i/k5rvwbvlcoqsw19ap0rp.gif)

We get a: `HTMLFormControlsCollection` - basically it's all of the stuff from inside the `form` from whence this submission event occurred.

## Turn `HTMLFormControlsCollection` into our _Object Literal_ via Array Methods - `filter` and `reduce`

!['Hold On To Your Butts'](https://images.app.goo.gl/Vda1qecNEoZniGLu6)

```javascript
Array.from(event.target.elements)
      .filter(({ id }) => id)
      .reduce((accumulator, { id, value }) => ({
        ...accumulator,
        ...{ [id]: value },
      }))
```

To quote from an EnVogue song, "And, now it's time for a breakdown..."

### `Array.from(event.target.elements)`

To use `filter` and `reduce` we first need to have an _array:_ `Array.from(event.target.elements)` 

### `filter` Out All Elements That Have an `id`

To better understand, we can first write like this one: `.filter(element => element.id)`

`filter` is a _predicate callback function._ This means that whenever it _only returns elements that are 'truthy.'_ `element => element.id` says, "Take in some element and **return** it _if_ it's true that it has a 🔑, id."

Now, we can use _object destructuring_ to shorten up that code. Instead of bringing in the whole `element` and then using `.` to try to access `id`, we can just 'pull out' the `id` 🔑 in the _parameter: `({id})`._ The rest of it works the same way. "Is there an id? If so, send this element back out." 

Yes, even though we are _destructuring_ the `id`, we still can _return_ the entire _element._ We don't lose anything here: `.filter(({ id }) => id)`

### `reduce` All The Things Down to 1 Object

`reduce` has a _callback function_ that takes in 2 _parameters._ The first represents an 'accumulator' - here that means the 'object' that we are 'building up.' As we _iterate_ over the _filtered_ elements, we want to keep 'building' and _returning_ this object, adding the next `id` and `value` (_object restructuring again_) each time.

```javascript
// The callback function inside of 'reduce'
(accumulator, { id, value }) => ({
          ...accumulator,
          ...{ [id]: value },
        })
```

Notice, `=> ({`. We are _implicitly returning_ an _object._ But, we need the `(` to clarify to JS that this is indeed what we are doing - otherwise, JS will be confused because we normally would have `{` to indicate that we are opening up our _function body._

`...accumulator,` is 'spreading' - `...` - all of the 🔑/value pairs inside of `accumulator`.

`...{ [id]: value }` temporarily wraps up the `id` and `value` from the current form element (as we are _iterating_) into an _object literal._ This is immediately 'spread' and open.

Now, the 'spreads' of both `accumulator` and `{[id]: value}` are 'merged' together into our 'returned object.' **This is what causes `accumulator` to 'accumulate' or grow upon each _iteration.**

```javascript
// Spread all the things and return a new 'merged' object
=> ({
  ...accumulator,
  ...{ [id]: value },
})
```

Regarding, `[` around `id` - I leave it to you to determine the reason for that. Try taking it out and see what happens.

## A Pure Function That Handles Any HTML Form Submission!

We have created a 'pure' function - one that can be 'copied/pasted' into any program anywhere and _w/o making any changes to its code,_ tt will just work! Our only assumption is that we are writing semantic, accessible HTML where `id`s are properly used for `input`s.