19

I'm trying to use .seralizeArray() to harvest form inputs values.

The input fields consist of a list of item with respective corresponding prices; I would like to save each value against its corresponding key pair but keep getting an error: ... empty array with 0 length.

I've tried a few combinations of selectors but still get [].

How can I serialize successfully?

Below is my code:

HTML

<fieldset id='itemInformation'>
    <h2>Items</h2>
    <div class="itemGroup">
        <input type="text" id="item1Name" value="Item 1" class="itemNames">
        <input type="number" step="0.01" id="item1Price" value="0.00">
    </div>
    <div class="itemGroup">
        <input type="text" id="item2Name" value="Item 2" class="itemNames">
        <input type="number" step="0.01" id="item2Price" value="0.00">
    </div>
    <div class="itemGroup">
        <input type="text" id="item3Name" value="Item 3" class="itemNames">
        <input type="number" step="0.01" id="item3Price" value="0.00">
    </div>

    <div class="changeNumber">
        <button class="increase">&#43;</button>
        <button class="decrease">&#8211;</button>
    </div>
    <div class="buttons">
        <button class="previousButton btn">Previous</button>
        <button class="nextButton btn">Next</button>
    </div>
</fieldset>

JS

$('#itemInformation .nextButton').bind('click', function (event) {
    event.preventDefault()

    console.log($('.itemGroup').serializeArray())
})
Mohit Tanwani
  • 6,608
  • 2
  • 14
  • 32

2 Answers2

42

Heads up!

You need to add a name attribute to all your <input> fields as in:

<input type="text" id="item1Name" value="Item 1" class="itemNames" name="itemNames">

Also, use <form> instead of <fieldset> unless you do have explicit reason for such a purpose.

The syntax for serializeArray(); is as follow: $(selector).serializeArray();.

Reference: w3schools (read on Definition and Usage ).

Same concept used here with the intention to serialize a collection of alike item.

Please note: using of the <form> element is not compulsory but simply recommended to get you easily and effectively serialize based on your intended purpose and information shared above in your post; I might have misread you on that, but the most important thing missing out was the name attribute, which accounts for your empty array [] as there's nothing available to be serialized.

Remember that based on your project requirements, you may have to make use of <fieldset> as and when required.

You may use the <fieldset> element with different ids to group related items you want to identify as a unit. As such, you may have something like this:

<form id="itemDetails">
    <fieldset id="itemInformation">
        <!-- itemInformation label and input fields -->
    </fieldset>
    <fieldset id="itemOrigin">
        <!-- itemOrigin label and input fields -->
    </fieldset>
    <fieldset id="itemDestination">
        <!-- itemDestination label and input fields -->
    </fieldset>
</form>

You can then use $('#itemDetails').serializeArray(); to serialize your entire form or $('#FIELDSET_ID').serializeArray(); where FIELDSET_ID is the corresponding id of a selected fieldset you want to serialize out of your form based on events so as to achieve your intended purpose.


Added the snippet below to illustrate how you can effectively pair up an item with it's corresponding value;

$('#itemInformation .nextButton').bind('click', function (event) {
    event.preventDefault();
    console.table($('#itemInformation').serializeArray());
    console.log($('#itemInformation').serializeArray());
});
<form id="itemDetails">
<!-- grouping all fieldset under a form element with an assigned id where
they can all be hierarchically referenced for precision where needed -->
    <fieldset id="itemInformation">
        <h2>Items</h2>
        <div class="itemGroup">
            <input type="number" id="item1Name" placeholder="0.00" class="itemNames" name="item1Name">
        </div>
        <div class="itemGroup">
            <input type="number" id="item2Name" placeholder="0.00" class="itemNames" name="item2Name">
        </div>
        <div class="itemGroup">
            <input type="number" id="item3Name" placeholder="0.00" class="itemNames" name="item3Name">
        </div>

        <div class="changeNumber">
            <button class="increase">&#43;</button>
            <button class="decrease">&#8211;</button>
        </div>
        <div class="buttons">
            <button class="previousButton btn">Previous</button>
            <button class="nextButton btn">Next</button>
        </div>
    </fieldset>
    <!-- other fieldset as necessary and harvest their input separately in
    a similar fashion as done with the first one itemInformation -->
    <fieldset id="itemOrigin">
        <!-- itemOrigin label and input fields -->
    </fieldset>
    <fieldset id="itemDestination">
        <!-- itemDestination label and input fields -->
    </fieldset>
</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

Below, a sample output of the above in a browser developer console (here: Google Chrome Browser);

sample output of the above snippet in Google Chrome Browser Developer Console

Also, available here (JSfiddle).

You will realise that each <div class="itemGroup"> has a single <input> element which has no value attribute but a placeholder to illustrate the expected input format. You may use value instead in case you want to pre-define a fixed value to be paired up against a corresponding item should there be no value entered. The name attribute is necessary: do not omit it.

As such (as above), when you serialize, the values collected from your input field will be paired up with the corresponding entered value and or default one(s).

Community
  • 1
  • 1
nyedidikeke
  • 6,899
  • 7
  • 44
  • 59
  • It's not compulsory to use `form` with `serializeArray()`. – Mohit Tanwani Oct 01 '16 at 17:35
  • Yes of course; it is not compulsory to use **`
    `** with **`serializeArray();`** to achieve the desired result. Did recommended that to further ease the process to the author of the question as he/she appears to be a beginner. Updated to include for more light on that.
    – nyedidikeke Oct 01 '16 at 17:56
  • @nyedidikeke can you go into just a little more detail as to why I shouldn't use fieldset. I'm building a page that moves from one fieldset to another as the user hits 'next' so fieldset seemed like the best option since it's one form. –  Oct 01 '16 at 21:17
  • @nyedidikeke related follow up, I've given each item the same name such as "item2" but I end up having an array with an object for each item and each price. How can I combine these objects. For instance, having one object that includes both the name of the item and it's price. Is this possible? –  Oct 01 '16 at 21:23
  • I said so based on your question; it shows you had the content you wanted to serialize nested under `
    ` and as such, the way you handled it in your JavaScript code suggest you are using `
    ` in place of `
    ` unless you explicitly want to serialize each *`
    `* under a higher container such as *``* *(I've referenced a non-form serialization alternative above)*. **TL;DR;** based on your question, adding a *`name`* attribute to input fields is a requirement. Also, using *`
    `*, not *``* will enable a successful serialization.
    – nyedidikeke Oct 02 '16 at 07:27
  • Based on your second comment (follow up question): it shows you've used *`
    `* in place of *`
    `* and added a `name` attribute to all your *``* fields. Your result (array of objects with each item mapping to their corresponding price) is exactly what is expected. To achieve mapping a given **item** to a given *price (to be collected as input data)*, you need for example **only** *``* *(no `value` attribute as that will be the input data to pair up with the `name` attribute)* under `
    `.
    – nyedidikeke Oct 02 '16 at 07:43
  • Updated my answer with more illustration and explanation as it require more words than allowed in content here. Do check it up for more explanation. – nyedidikeke Oct 02 '16 at 10:56
7

The .serializeArray() method uses the standard W3C rules for successful controls to determine which elements it should include; in particular the element cannot be disabled and must contain a name attribute.

IMO, Use form and apply name attributes to all the inputs.

var formdata = $( "#itemInformation" ).serializeArray();

FYI, use form is a good practice but it's not compulsory to use that.

Official documentation serializeArray()

$('#itemInformation .nextButton').bind('click', function (event) {
    event.preventDefault()

    console.log($('#itemInformation').serializeArray())
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<fieldset id='itemInformation'>
        <h2>Items</h2>
        <div class="itemGroup">
            <input type="text" id="item1Name" name="item1Name" value="Item 1" class="itemNames">
            <input type="number" step="0.01" name="item1Price" id="item1Price" value="0.00">
        </div>
        <div class="itemGroup">
            <input type="text" id="item2Name" name="item2Name" value="Item 2" class="itemNames">
            <input type="number" step="0.01" name="item2Price" id="item2Price" value="0.00">
        </div>
        <div class="itemGroup">
            <input type="text" name="item3Name" id="item3Name" value="Item 3" class="itemNames">
            <input type="number" step="0.01" name"item3Price" id="item3Price" value="0.00">
        </div>

        <div class="changeNumber">
            <button class="increase">&#43;</button>
            <button class="decrease">&#8211;</button>
        </div>
        <div class="buttons">
            <button class="previousButton btn">Previous</button>
            <button class="nextButton btn">Next</button>
        </div>
    </fieldset>
Mohit Tanwani
  • 6,608
  • 2
  • 14
  • 32