Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[request] Include unchecked checkbox in result #33

Open
ikhsan017 opened this issue Sep 19, 2014 · 13 comments
Open

[request] Include unchecked checkbox in result #33

ikhsan017 opened this issue Sep 19, 2014 · 13 comments
Milestone

Comments

@ikhsan017
Copy link

Hi @macek ,

It is possible to add feature to include unchecked checkbox into the object or json result, something like

{
    "some_unchecked_checkbox" : false
}

regards
Ikhsan

@macek
Copy link
Owner

macek commented Sep 19, 2014

@ikhsan017 this is unlikely to be implemented as this project is moving forward to meet the specs described for W3C HTML JSON form submission

Unchecked checkboxes are not meant to be submitted to the server, but this is not really a big problem.

Think of it this way:

<!-- client side -->
<form>
  Email: <input name="email" value="[email protected]">
  <input type="checkbox" name="newsletter">Receive News Letter?
</form>
<script>
  var xhr = $post("/update-profile", $("form").serializeObject());
  // ...
</script>

Then in /update-profile you can get both true and false values for the checkbox quite easily

// server side
app.post("/update-profile", function() {
  var email = req.param("email");
  var newsletter = Boolean(req.param("newsletter"));
  // ...
});

If the newsletter value isn't present in the form submission, it's implicitly false and the app can easily detect that.


In case this example is a little confusing, let's look at it one more way.

req.param("newsletter") can be set to one of two values.

  • if the <input> is checked, the value will be set to "on".
  • if the <input> is unchecked, it will not be submitted, and when we check for the value, it will be unset or null.

By simply casting the value as a Boolean, we get both states

Boolean("on"); // true
Boolean(null); // false

We now have a perfectly toggling checkbox without submitting the unchecked checkbox to the server


Because this is such a popular request, I'm tempted to make it an option for this plugin. However, larger organizations such as W3C and jQuery are leaning on one another here.

W3C says "don't submit unchecked checkboxes" and jQuery is saying "we use the standard W3C rules".

This plugin depends on the output of jQuery.serializeArray so the scope of this plugin doesn't even know that unchecked checkboxes exist!

This is not the first time .serializeArray has come up in the issues of this plugin. serializeArray doesn't give us any information on the type of value (i.e., text, number, boolean, etc); everything is just treated as text. We already have to remove it as a dependency if we're going to meet the W3C JSON form submission spec.

I've already started working on my own serializer that would give this plugin some more flexibility in terms of user options. Things like {serializeWithType: true} or {includeUncheckedInputs: true} could be a possibility.

I'll leave this open to see what other people have to say about it. I suspect most people are requesting the "submit unchecked checkboxes" because they don't realize that there's still a way to detect the value as true / false on the server side. If this is the case, we want to educate people rather than implement new features to help people do things the "wrong" way.

Feel free to reply in this thread if you have any other questions or ideas ✌️

@ikhsan017
Copy link
Author

Yeah, I got it, as implementation on major browser also have same behavior. But in my case, I am saving the form data as json-encoded data and put it into some textarea and need a clear state of the checkbox.

scanning it like using $('[type=checkbox]:not(:checked)') should be fine, but put it in the object will little bit harder when it has name like input[child][grandchild][etc] since I am not so fluent with regex matching :D

Create an optional parameter to parse unchecked checkbox should be fine too, and follow the standard by default.

btw, I found it already implemented here https://github.com/marioizquierdo/jquery.serializeJSON , quite similar project to yours :)

regards
Ikhsan

@macek
Copy link
Owner

macek commented Sep 19, 2014

@ikhsan017 yup I'm aware of his project, but I disagree with some of the implementation details. Also, his checklist of how his project is "better" maybe have been true at the time he wrote it, but that's no longer the case.

I'll keep you updated here with the any related progress.

@macek macek added this to the 3.x milestone Sep 23, 2014
@markkemper1
Copy link

@macek Just like to add my use case to this discussion .

We call serializeObject() on the form and then merge it into another object. So not have the false value for some properties is causing us headaches (doesn't update the other object because the property doesn't exist).

Agreed it shouldn't be enabled by default but for the cases where you are using the object client side (rather then just submitting the form to the server), its really needed to get a complete representation of the object (we now have to go an manually insert the false value)

Hope this makes sense.

@markkemper1
Copy link

Ended up adding a extra method onto the FormSerializer to support this because trying to work around it ended up being a nightmare.

FormSerializer.prototype.serializeObjectIncludingUnchecked = function() {

    if (this.length > 1) {
        return new Error("jquery-serialize-object can only serialize one form at a time");
    }

    var formSerializer = new FormSerializer($, this);

    var pairs = this.serializeArray();

    //Add in unchecked checkbox values.
    var results = this.find(':checkbox:not(:checked)').clone().prop('checked', true).serializeArray();

    for (var i = 0; i < results.length; i++) {
        results[i].value = results[i].value === "true" ? false : null; //could support an attribute on the input to determine unchecked value, but this should be good enough for now. 
    }

    pairs = pairs.concat(results);

    return formSerializer.addPairs(pairs).serialize();
};

@macek
Copy link
Owner

macek commented Jul 16, 2015

@markkemper1 you might want to make sure you're modifying the latest version 2.5.0

2.5.0 will allow .serializeObject to be called on multiple elements so you could do

var $uncheckedInputs = $('#my-form :checkbox:not(:checked)').clone().prop('checked', true);
var obj = $('#my-form :input').add($uncheckedInputs).serializeObject();

Sorry for the delay on adding this feature to the latest version. Hope this helps a little better.

@markkemper1
Copy link

Not sure that will help as I need to set the value to false in the resulting js object. In your example the properties would end up with true (or the value of the value attribute) ?.

I only set the value to true, so that serializeArray will include the key / value pairs.

The code does the following:

  • Gets the unchecked boxes, creates a copy, sets the checked attribute (so they will be serialized) and serializes them into an array
  • Then goes through each item in the array and sets (back) all the values back to false
  • Then add these resulting pairs to the normal function of the library.

@macek
Copy link
Owner

macek commented Jul 16, 2015

@markkemper1, My bad, I kinda just glanced at your code and threw and example together. The idea in principle would still work though: add additional fields - whatever they might be - to be serialized along with your other form fields.

Maybe this will help lead you to a more complete solution

function mySerializeFunction($form) {
  var $uncheckedInputs = $form.find(':checkbox:not(:checked)').clone().map(function() {
    return $(this).prop('checked', true).val(false);
  });
  return $form.find(':input').add($uncheckedInputs).serializeObject();
}

var obj = mySerializeFunction($('#my-form'));

Again, it's not tested, but you can construct the additional fields however you want. A modification of the core plugin should not be necessary.

@markkemper1
Copy link

Thanks, that looks better but (just glancing the source) won't the value be
a string "false" instead of the literal false?

On 16 July 2015 at 14:40, Paul Maček [email protected] wrote:

My bad, I kinda just glanced at your code and threw and example together.
The idea in principle would still work though: add additional fields -
whatever they might be - to be serialized along with your other form fields.

Maybe this will help lead you to a more complete solution

function mySerializeFunction($form) {
var $uncheckedInputs = $form.find(':checkbox:not(:checked)').clone().map(function() {
return $(this).prop('checked', true).val(false);
});
return $form.find(':input').add($uncheckedInputs).serializeObject();
}
var obj = mySerializeFunction($('#my-form'));

Again, it's not tested, but you can construct the additional fields
however you want. A modification of the core plugin should not be necessary.


Reply to this email directly or view it on GitHub
#33 (comment)
.

@macek
Copy link
Owner

macek commented Jul 16, 2015

@markkemper1 version 2.4.0 received support for serializing booleans, but only for type="checkbox" inputs.

Serializing the other types (like type="number") are targeted for 3.x - which I haven't had a ton of time to work on lately.


Edit

Looking at it closer, you're right, the value would be the string value "false" because of the hacked way Boolean encoding works in 2.x

It looks like the checkboxes have to be children of the selector (variable $form in this scope). This is just another nasty side effect of jQuery's serializeArray function. Add another tally...

Anyway, if you must get the boolean value of your unchecked checkboxes, I guess your other solution might be the only way for right now. Sorry if I've wasted any of your time.

@dandv
Copy link

dandv commented Aug 31, 2015

@marioizquierdo, any comments on #33 (comment) ?

@marioizquierdo
Copy link

It's true I wrote the "why it's better" a while ago and certain checks don't really differentiate serializeJSON anymore. I just updated the README file with more accurate info in this regard.

Also, implementing unchecked checkboxes in jquery.serializeJSON was not easy. It complicated the interface, the implementation and the available use cases, but there was hight demand for it.

Relying on serializeArray is good overall and ensures a perfect standard behavior, but it won't include non-standard elements like unchecked checkboxes. Blame HTML for that ;)

@rhyzx
Copy link

rhyzx commented Feb 20, 2016

Solution:

const $target = $(target)
const data = new FormSerializer($, $target)
.addPairs($target.serializeArray())
// add unchecked value
.addPairs(
  $target.find(':checkbox[name]:not(:checked)')
  .toArray()
  .map(checkbox => ({name: checkbox.name, value: false}))
)
.serialize()

@macek macek mentioned this issue Apr 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants