5

I have a JSON array:

info = [{"name":"abc", "rank" : 1},{"name":"xyz", "rank":2},{"name":"pqr", "rank":3}];

and I am trying to pass it as an input value to a hidden field using jQuery and send it to the server with a POST request.

$('<form action="/info/saveAll" method="POST"/>')
        .append($('<input type="hidden" name="info" value="' + JSON.stringify(info) + '">'))
        .appendTo($(document.body))
        .submit();

At the server end, I am accessing the value of info as:

router.route('/saveAll')
    .post((req, res) => {
       let info = JSON.parse(req.body.info);
       console.log(info); //SyntaxError: Unexpected end of JSON input
    })

If I don't stringify the array before submit, then the typeof info still returns string inside the post and when I try to parse the string type I get syntax error like SyntaxError: Unexpected token o in JSON at position 1.

I know this can be done by just doing it through an ajax post request, but I wanted a work around that does not involve an ajax request.

Any help would be great.

Emma
  • 27,428
  • 11
  • 44
  • 69
hushie
  • 417
  • 10
  • 23
  • @Emma it did not work with trim, or if I use concat. and the post you suggested has ajax request. I mentioned in my question that I don't want to use ajax request. – hushie Feb 02 '19 at 07:05
  • 1
    @Emma the problem is that the generated HTML is corrupted, because a JSON string can contain reserved characters like `"`. – Stefan Becker Feb 02 '19 at 07:58

1 Answers1

4

You can't simply concatenate a JSON string into HTML, because it can contain reserved characters, like ", that need to be quoted. Just comment out the .submit() and check the hidden input field your code added to the DOM with DOM Inspector in your browser developer tools. You'll see that the value= attribute is corrupted.

The solution is simple: use encodeURI() instead, i.e.

.append($(
    '<input type="hidden" name="info" value="' +
    encodeURI(JSON.stringify(info)             + 
    '\'>'))

and

let info = JSON.parse(decodeURI(req.body.info));

Now you'll see that the attribute is shown as valid JSON string in the DOM inspector. When you select "Edit as HTML" menu on your hidden input element you'll see a quoted string in the HTML text for the value= attribute.

From my manual test with Firefox:

Incorrect

const info = {
          test: "somestring",
          html: '<input type="hidden" value="&"/>',
      };
$('#demo').append($(
        '<input type="hidden" value="' +
        JSON.stringify(info))          +
        '">'));

The generated HTML:

<input type="hidden" value="{" test":"somestring","html":"<input="">

Correct

const info = {
          test: "somestring",
          html: '<input type="hidden" value="&"/>',
      };
$('#demo').append($(
        '<input type="hidden" value="'   +
        encodeURI(JSON.stringify(info))) +
        '">'));

The generated HTML:

<input type="hidden" value="%7B%22test%22:%22somestring%22,%22html%22:%22%3Cinput%20type=%5C%22hidden%5C%22%20value=%5C%22&amp;%5C%22/%3E%22%7D">

Another option is to use a HTML entities encode/decode method, f.ex. this SO question, but the provided answers seem to be more cumbersome than my solution. It would be easier to use a npm module instead, e.g. entities.


Or simply...

... don't rely on HTML string parsing and let jQuery do all the work. It also removes the need to use decodeURI() on the server side:

const info  = {
          test: "somestring",
          html: '<input type="hidden" value="&"/>',
      },
      input = $('<input type="hidden"/>')
          .val(JSON.stringify(info));
$('#demo')
      .append(input);

The generated HTML:

<input type="hidden" value="{&quot;test&quot;:&quot;somestring&quot;,&quot;html&quot;:&quot;<input type=\&quot;hidden\&quot; value=\&quot;&amp;\&quot;/>&quot;}">
Stefan Becker
  • 5,695
  • 9
  • 20
  • 30