1

I've got code that takes form fields and converts them into a JSON string suitable for passing to a REST API (the marathon REST API specifically). The problem is that JSON.stringify double quotes all the form field values, even those that are numeric, which causes the ajax call to fail. Here's the string my code is producing:

{"id":"basic-1","cpus":"0","mem":"32","instances":"1","cmd":"while [ true ] ; do echo 'Hello Marathon' ; sleep 5 ; done"}

The mem, cpus, and instances values should not be double quoted because they're numeric.

data: JSON.stringify($('form').MytoJson());

MytoJson is a function that serializes the form fields. That's working fine. The problem is that JSON.stringify is putting the quotes around the keys and all the values, including the numeric values, which is causing the ajax call to fail.

The JSON.stringify function takes two arguments. The first argument is a replacer function, which can be a function or an array. Consider this replacer function:

function replacer(key, value) {
    if (typeof value === "string") {
        return undefined;
    }
    return value;
}
JSON.stringify($('form').MytoJson(), replacer);

I want to modify this replacer function to not quote numeric values. I'm wondering if I have use the HTML5 form attributes to differentiate between string and numeric form fields? Consider this form field:

<input id="cpus" type="number" name="cpus" value="0.1" />

How can I use the fact that this field has the attribute type="number" in the replacer function? I want to modify the replacer function to not quote values when the form field is of type number.

Robert Stober
  • 53
  • 1
  • 7
  • 1
    This shouldn't cause the ajax call to fail - I am guessing you are using a POST or a PUT - this should still send the data to your service - what you will need to do is in your service to then convert these string value to numeric before passing to your database. It is standard procedure to stringify numerics before posting them to a restful service. – Sprose Apr 06 '17 at 09:05

4 Answers4

2

I'm not 100%, but I imagine the issue is being caused by the the code that reads the form fields' values - namely it is reading the values as strings (which they are).

What you need to do is cast any numeric values to an actual JS Number. Try the following replacer function:

function replacer( key, value ) {

    var ret = ( value === value * 1 )
            ? value * 1
            : value;

    return ret;

}

This should check if each value is numeric, and if so convert it to a Number

SimonR
  • 1,248
  • 9
  • 10
  • You're right. The key was to convert the numeric fields to floating point numbers. I'm surprised that there's no library to do this already - to look at the form field type and convert the data to the appropriate type for the JSON string. Or maybe I just didn't find it. – Robert Stober Aug 01 '16 at 19:00
1

In order to turn a stringifyed string back into data, you would use JSON.parse(stringifyedString);

Simply removing the quotes from a string won't convert "5" into a Number, for example. It'll just make a string with the character 5.

TrampolineTales
  • 808
  • 3
  • 14
  • 31
  • Good point. I'm now using `parseFloat()` to convert the string into a floating point number in my reducer function. Please see above. – Robert Stober Aug 01 '16 at 18:58
0

Here's the solution. I've modified the replacer function to use the HTML5 form field type to discriminate between form fields that should be quoted or not quoted.

function replacer(key, value) {
    //console.log(typeof($(eval('\'#' + key + '\'')).attr('type')));
    if ($(eval('\'#' + key + '\'')).attr('type') == null) {
        return value;
    }
    return parseFloat(value);
} 

Then in my ajax code:

 data: JSON.stringify($('form').MytoJson(), replacer);

It seems that the 'type' attribute for standard 'text' input fields is undefined, but it is defined when the type is 'number'. I'm using that.

If the type attribute is undefined I just return the value which gets included and double quoted in the JSON string. But if the type attribute is defined, then I cast the value to a float. It gets included in the JSON string un-quoted. This is a working solution for now but I'm sure I'll have to re-visit this in the near future.

Robert Stober
  • 53
  • 1
  • 7
0

You need to give JSON.stringify() a replacer function to transform the results.
Like this:

JSON.stringify(x, (key, value) => (isNaN(value) ? value : +value))

The isNan() function takes a number and checks if it is NaN.
If you pass it something that is not of type number, it is converted to number or NaN.

The Unary plus +value returns the value as number if value indeed contains a number, or NaN otherwise.

Marco Castanho
  • 395
  • 1
  • 7
  • 24