Skip to content

Commit

Permalink
Integrate readCheckboxUncheckedValues into the new serializeArray met…
Browse files Browse the repository at this point in the history
…hod to simplify the serialization process for unchecked checkboxes
  • Loading branch information
marioizquierdo committed Dec 31, 2020
1 parent 5d0c68d commit 4458bc7
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 45 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ $('form').serializeJSON();
}
```

Form input, textarea and select tags are supported. Nested attributes and arrays can be specified by using the `attr[nested][nested]` syntax.
Form input, textarea and select tags are supported. Nested attributes and arrays can be specified by naming fields with the syntax: `name="attr[nested][nested]"`.

HTML form:
```html
Expand Down Expand Up @@ -114,7 +114,7 @@ $('#my-profile').serializeJSON();
}
```

The `serializeJSON` function returns a JavaScript object, not a JSON String. The plugin should probably have been called `serializeObject` or similar, but those plugins already existed.
The `serializeJSON` function returns a JavaScript object, not a JSON String. The plugin should probably have been called `serializeObject` or similar, but that plugin name was already taken.

To convert into a JSON String, use the `JSON.stringify` method, that is available on all major [new browsers](http://caniuse.com/json).
If you need to support very old browsers, just include the [json2.js](https://github.com/douglascrockford/JSON-js) polyfill (as described on [stackoverfow](http://stackoverflow.com/questions/191881/serializing-to-json-in-jquery)).
Expand Down Expand Up @@ -471,7 +471,8 @@ Contributions are awesome. Feature branch *pull requests* are the preferred meth
Changelog
---------

* *3.1.1* (Dev 30, 2020): Update #114 (Allow to use new versions of jQuery by avoiding calls to the deprecated method `jQuery.isArray`).
* *3.2.0* (draft): ... TODO: update comment: https://github.com/marioizquierdo/jquery.serializeJSON/issues/67
* *3.1.1* (Dec 30, 2020): Update #114 (Allow to use new versions of jQuery by avoiding calls to the deprecated method `jQuery.isArray`).
* *3.1.1* (Nov 09, 2020): Bugfix #110 (Allow unindexed arrays with multiple levels of nested objects).
* *3.1.0* (Sep 13, 2020): Rename option `disableColonTypes` that was mistakenly named `disableSemicolonTypes`. Fix typos in README.
* *3.0.0* (Sep 06, 2020): Improve types (PR #105) and remove parsing options (PR #104). The type system with `:type` suffixes, `data-value-type` attributes, and a combination of the options `customTypes`, `disableColonTypes` and `defaultType`, are safer and easier to use than the previous options `parseNumbers`, `parseAll`, etc. Thanks [Laykou](https://github.com/Laykou) for suggesting [PR #102] that pointed the problems of inputs with colons in their names.
Expand Down
71 changes: 32 additions & 39 deletions jquery.serializejson.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@
var typeFunctions = $.extend({}, opts.defaultTypes, opts.customTypes);

// Make a list with {name, value, el} for each matched element.
var formAsArray = f.serializeArray($form);
f.readCheckboxUncheckedValues(formAsArray, opts, $form); // add objects to the array from unchecked checkboxes if needed
var serializedArray = f.serializeArray($form, opts);

// Convert the formAsArray into a serializedObject with nested keys
// Convert the serializedArray into a serializedObject with nested keys
var serializedObject = {};
$.each(formAsArray, function (_i, obj) {
$.each(serializedArray, function (_i, obj) {
var ogName = obj.name; // original input name
var ogValue = obj.value; // original input value

Expand Down Expand Up @@ -123,26 +122,39 @@
return $.extend({}, f.defaultBaseOptions, f.defaultOptions, options);
},

// Similar to jQuery serializeArray, returns an array of objects with name and value,
// but in addition has the dom element, so it can be referenced later for configuration data attrs.
serializeArray: function($form) {
// Just like jQuery's serializeArray method, returns an array of objects with name and value.
// but also includes the dom element (el) and is handles unchecked checkboxes if the option or data attribute are provided.
serializeArray: function($form, opts) {
if (opts == null) { opts = {}; }
var f = $.serializeJSON;

return $form.map(function() {
var elements = $.prop(this, "elements"); // handle propHook "elements" to filter or add form elements
return elements ? $.makeArray(elements) : this;

}).filter(function() {
var $el = $(this);
var type = this.type;
return this.name &&
!$( this ).is(":disabled") && // .is(":disabled") so that fieldset[disabled] works
rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && // only form fields
(this.checked || !rcheckableType.test(type)); // remove unchecked checkboxes

// Filter with the standard W3C rules for successful controls: http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
return this.name && // must contain a name attribute
!$el.is(":disabled") && // must not be disable (use .is(":disabled") so that fieldset[disabled] works)
rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && // only serialize submittable fields (and not buttons)
(this.checked || !rcheckableType.test(type) || f.getCheckboxUncheckedValue($el, opts) != null); // skip unchecked checkboxes (unless using opts)

}).map(function(_i, el) {
var val = $(this).val();
var $el = $(this);
var val = $el.val();
var type = this.type;

if (val == null) {
return null;
}

if (rcheckableType.test(type) && !this.checked) {
val = f.getCheckboxUncheckedValue($el, opts);
}

This comment has been minimized.

Copy link
@aleen42

aleen42 Jul 9, 2021

@marioizquierdo There are two problems:

  1. Cannot assume that getCheckboxUncheckedValue returns a string value, which should throw an exception when it is not a string by calling val.replace(rCRLF, '\r\n').
  2. radio is not a checkbox, and it has broken when we want to only set unchecked value for input[type=checkbox]

This comment has been minimized.

Copy link
@aleen42

aleen42 Jul 9, 2021


if (isArray(val)) {
return $.map(val, function(val) {
return { name: el.name, value: val.replace(rCRLF, "\r\n"), el: el };
Expand All @@ -154,6 +166,14 @@
}).get();
},

getCheckboxUncheckedValue: function($el, opts) {
var val = $el.attr("data-unchecked-value");
if (val == null) {
val = opts.checkboxUncheckedValue;
}
return val
},

// Parse value with type function
applyTypeFunc: function(name, valStr, type, typeFunctions) {
var typeFunc = typeFunctions[type];
Expand All @@ -163,33 +183,6 @@
return typeFunc(valStr);
},

// Fill the formAsArray object with values for the unchecked checkbox inputs,
// using the same format as the jquery.serializeArray function.
// The value of the unchecked values is determined from the opts.checkboxUncheckedValue
// and/or the data-unchecked-value attribute of the inputs.
readCheckboxUncheckedValues: function (formAsArray, opts, $form) {
if (opts == null) { opts = {}; }

var selector = "input[type=checkbox][name]:not(:checked):not([disabled])";
var $uncheckedCheckboxes = $form.find(selector).add($form.filter(selector));
$uncheckedCheckboxes.each(function (_i, el) {
// Check data attr first, then the option
var $el = $(el);
var uncheckedValue = $el.attr("data-unchecked-value");
if (uncheckedValue == null) {
uncheckedValue = opts.checkboxUncheckedValue;
}

// If there's an uncheckedValue, push it into the serialized formAsArray
if (uncheckedValue != null) {
if (el.name && el.name.indexOf("[][") !== -1) { // identify a non-supported
throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+el.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");
}
formAsArray.push({name: el.name, value: uncheckedValue});
}
});
},

// Splits a field name into the name and the type. Examples:
// "foo" => ["foo", ""]
// "foo:boolean" => ["foo", "boolean"]
Expand Down
15 changes: 12 additions & 3 deletions spec/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -825,16 +825,25 @@ describe("$.serializeJSON", function() {
});
});

it("does not work on a nested list of objects", function() {
it("works on a nested list of objects", function() {
$form = form([
inputCheckbox("answers[][correct]:boolean", "true").attr("data-unchecked-value", "false"),
inputText("answers[][text]", "Blue"),

inputCheckbox("answers[][correct]:boolean", "true").attr("data-unchecked-value", "false"),
inputText("answers[][text]", "Green"),
]);

expect(function(){$form.serializeJSON();}).toThrow(); // it throws a descriptive error for the user
inputCheckbox("answers[][correct]:boolean", "true").attr("data-unchecked-value", "false").prop("checked", true),
inputText("answers[][text]", "Red"),
]);
obj = $form.serializeJSON({checkboxUncheckedValue: "false"});
expect(obj).toEqual({
answers: [
{correct: false, text: "Blue"},
{correct: false, text: "Green"},
{correct: true, text: "Red"},
],
});
});

it("does not serialize disabled checkboxes", function() {
Expand Down

0 comments on commit 4458bc7

Please sign in to comment.