Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST unchecked checkboxes with values to Node [duplicate]

I have an HTML form with an array of checkboxes (using [] naming). I need to be able to process this with express. I'm using body-parser.

The problem is that unchecked checkboxes don't submit a value, and at the same time, body-parser seems to remove "holes" in arrays by simply packing the values into an array in order of indices, but ignoring the indices themselves. (Update: Actually it looks like qs is the culprit).

Consider this full example, which displays a form and responds with a JSON dump of the submitted data:

Install:

npm install express body-parser

index.js:

var express = require("express");
var site = express();

site.use(require("body-parser").urlencoded({extended:true}));

site.get("/", function (req, res) {
    res.sendFile(__dirname + "/test.html");
});

site.post("/form", function (req, res) {
    res.json(req.body);
});

site.listen(8081);

test.html:

<html>
    <body>
        <form method="post" action="/form">
            <input type="checkbox" name="option[0]" value="1">
            <input type="checkbox" name="option[1]" value="1">
            <input type="checkbox" name="option[2]" value="1"><br>
            <input type="text" name="text[0]"><br>
            <input type="text" name="text[1]"><br>
            <input type="text" name="text[2]"><br>
            <button type="submit">Submit</button>
        </form>
    </body>
</html>

In that example, if I were to check only option[1], I verify that the index is set correctly by inspecting the request in Chrome, body is:

option[1]:1
text[0]:
text[1]:
text[2]:

Yet body-parser collapses the option array and produces the following in req.body:

{"option":["1"],"text":["","",""]}

As you can see, text has all three, but option has only one item. Similarly, if I were to check option[0] and option[2], the request body would look like:

option[0]:1
option[2]:1
text[0]:
text[1]:
text[2]:

But it would be parsed to:

{"option":["1","1"],"text":["","",""]}

I lose all information about which checkbox was checked.

My question is, how do I do this? What I want to happen is, e.g.:

  • With checkbox[1] checked:

    {"option":[null,"1",null],"text":["","",""]}
    
  • With checkbox[0] and checkbox[2] checked:

    {"option":["1",null,"1"],"text":["","",""]}
    

I'm not actually married to null and "1", I just need falsey and truthy.

Also, it is important that I not lose information about how many checkboxes should be in the array. For example, if I were to give each checkbox a unique value, I suppose I could translate "option":["0","1"] into an array of boolean values, except I would lose the knowledge that the array is of size 3 (with the 3rd value false in that case) -- although I guess I could add e.g. a hidden input like numberOfCheckboxes=3, but... this kind of mapping is cumbersome and I'd like to avoid it if possible.

like image 655
Jason C Avatar asked Nov 18 '22 01:11

Jason C


1 Answers

My approach requires no javascript on client side. Add hidden fields as many as your checkboxes with same names

body parser will parse checked items as array and string others

I meant

<input type="hidden" name="option[0]" value="0">
<input type="hidden" name="option[1]" value="0">
<input type="hidden" name="option[2]" value="0">
<input type="checkbox" name="option[0]" value="1">
<input type="checkbox" name="option[1]" value="1">
<input type="checkbox" name="option[2]" value="1">

If your option[1] is checked then body parser will parse it like

{option:['0', ['0', '1'], '0']}

And here is the modifier

req.body.option = req.body.option.map(item => (Array.isArray(item) && item[1]) || null);

so now body will be

{option: [null, '1', null]}
like image 158
Tolgahan Albayrak Avatar answered Dec 31 '22 09:12

Tolgahan Albayrak