69

Is there some rationale for val() being useless for checkbox controls, whereas it is useful for getting input data consistently across every other input control?

e.g. for checkboxes, at appears to always return "on" regardless of the checkbox state. For other input controls that don't actually have a "value" attribute, e.g. select and textarea, it behaves as you would expect. See:

http://jsfiddle.net/jamietre/sdF2h/4/

I can't think of a good reason why it wouldn't return true or false. Failing that, at least return "on" only when checked, and an empty string when not. Failing that, at least always return an empty string, given that checkboxes have no value attribute!

Obviously I know how to get the value using attr, but here's the situation. I am developing a simple (so far anyway) C# jQuery implementation to do HTML parsing on the server, and I am trying to be completely faithful to jQuery's implementation so it behaves consistently on either the client or server against the same DOM. But this just seems stupid and I'm having a hard time getting myself to actually code "value" to return "ON" for a checkbox no matter what. But if I don't, it won't be consistent. So I'm trying to understand, is there some reason for doing this? Does it serve some purpose, or is it simply an artifact of some kind? Would anyone ever use the val() method against a checkbox, if so, why? If not, why did the jQuery architects decide on this approach to make it not useful?

casperOne
  • 73,706
  • 19
  • 184
  • 253
Jamie Treworgy
  • 23,934
  • 8
  • 76
  • 119
  • 1
    This is most bizarre, but it IS javascript. Just go with attr('checked') and sadly you have to not be consistent. :| – ohmusama Apr 11 '11 at 12:41
  • @mcgrailm — Why? The end tags for options are explicitly optional in every version of the HTML specification in which they have appeared at all. – Quentin Dec 30 '22 at 10:37

8 Answers8

81

I can't think of a good reason why it wouldn't return true or false. Failing that, at least return "on" only when checked, and an empty string when not. Failing that, at least always return an empty string, given that checkboxes have no value attribute!

Checkboxes do have a value attribute. It's quite common to use it in eg. multi-checkboxes in forms, for example:

<input type="checkbox" name="foo[]" value="1" />
<input type="checkbox" name="foo[]" value="2" />

Then when user submits the form, the server can parse which of the checkboxes were checked by checking the values of the foo[] array. The value of the checkbox does not change whether it is checked or not; the browser simply does not send the values of unchecked checkboxes to the server. If you do eg. $('#your-form').serialize()in jQuery, it should work similarly; it shouldn't include values of unchecked checkboxes. If you omit the value from checkbox, it simply defaults to on.

If you want to check whether an individual checkbox is checked or not in jQuery, the best most descriptive way is to do $(this).is(':checked')

reko_t
  • 55,302
  • 10
  • 87
  • 77
  • 2
    Okay. That makes sense. Jees. I have abstracted myself from HTML for so long because of asp.net I forgot the basics of how checkboxes work. – Jamie Treworgy Apr 11 '11 at 12:46
  • 8
    You know as much as I understand this, I still think that a more intuitive approach would be to return true or false. You can always use `attr('value')` if that's what you want. Seems to defeat the purpose of the abstraction. – Jamie Treworgy Apr 11 '11 at 12:51
  • 1
    @jamietre this is your own vision of abstraction... if val() was returning the value of text inputs and the checked state of checkbox inputs, I would probably cry and stop using jQuery :-) – Capsule Apr 11 '11 at 13:03
  • 18
    Why? If the purpose of "val" is simply to return the contents of the "value" attribute, then it would be pointless. That's not what it does. It returns the inner HTML of a text area, the selected option of a `select` list, and ... the "value" attribute of a checkbox. In every other type of control, it returns information related to the current form state. The docs describe val as: "Get the current value of the first element in the set of matched elements." and then go on to explicity say .. "except for checkboxes, where you can use :checked." It's totally counterintuitive. – Jamie Treworgy Apr 11 '11 at 13:09
  • But that is exactly what it does.. It gets the value of the first matched checkbox! Imho it'd be silly that you'd have to use another way to get the value if the checkbox was unchecked. When you want to get a "snapshot" of a form state, you don't usually iterate through the inputs one-by-one anyway, you rather just use `.serialize()` of jQuery, which won't include any values for checkboxes that are not checked. – reko_t Apr 11 '11 at 13:24
  • 6
    +1, though `this.checked` is far nicer (and probably orders of magnitude quicker) than `$(this).is(':checked')`. – lonesomeday Apr 11 '11 at 14:58
12

You say that "checkboxes have no value attribute". On the contrary: the value attribute is optional except on checkboxes and radio boxes.

From the W3C specifications:

[the value attribute] is optional except when the type attribute has the value "radio" or "checkbox"

on is the default value that your browser gives the element when you ignore the specification and don't set a value attribute.

You need to remember what the value means: it is sent with the name of the element to the server when the form is submitted. If it is not checked, the value is not sent. The value on is therefore only sent when the checkbox is checked.

lonesomeday
  • 233,373
  • 50
  • 316
  • 318
  • 2
    +1 We learn something new everyday. Thanks lonesomeday. This is funny.. I've been working in the web years but never considered to read the W3C spec for checkboxes, or have any interest to investigate where "on" came from, although it's crossed my mind the odd occasion. (been through many other W3C specs tho..) Now I know. Makes sense! And now for something completely different – Tom Pace Apr 17 '14 at 03:27
4

Perhaps this should help

$(document).ready(function() {
    $('input[type=checkbox]').click(function() {
      alert("val="+$(this).val()+",checked="+$(this).attr('checked'));
    });

});

Use input[type=checkbox] to select input type="checkbox" since checkbox is and input with type="checkbox"

And also put value attribute to checkbox.

On jsfiddle

UPDATE

<form method="post" action="#">
    PHP<input type="checkbox" name="ch[]" value="PHP"><br/>
    JS<input type="checkbox" name="ch[]" value="JS"><br/>
    JAVA<input type="checkbox" name="ch[]" value="JAVA"><br/>
    PYTHON<input type="checkbox" name="ch[]" value="PYTHON"><br/>
    <input type="submit" name="submit"/>
</form>

And php

if($_POST){
foreach($_POST['ch'] as $post => $value){
    echo "$post -> $value <br/>";
}
}

They all share same name as they are a common group of button. You you know which was checked and which was not through their values.

The other way is

if($_POST){
    foreach($_POST as $post => $value){
        echo "$post -> $value <br/>";
    }
}

<form method="post" action="#">
    PHP<input type="checkbox" name="PHP"><br/>
    JS<input type="checkbox" name="JS"><br/>
    JAVA<input type="checkbox" name="JAVA"><br/>
    PYTHON<input type="checkbox" name="PYTHON"><br/>
    <input type="submit" name="submit"/>
</form>

But the previous seems to add more dynamic and less tedious(I would believe).

And as to @Capsule's question

alert("val="+$(this).val()+",checked="+$(this).attr('checked'));
<input type="checkbox"> Check me.

returns the value on i believe that's the default value of the check-box.

And the second experiment also give the on value.

I hope I am not wrong.

S L
  • 14,262
  • 17
  • 77
  • 116
  • I linked the wrong version of the fiddle, sorry, it has been fixed. It does what I say it does. – Jamie Treworgy Apr 11 '11 at 12:38
  • OK, sure, you can add a "value" attribute to a checkbox and it will return that. Why is that useful or intuitive, since it's an input control? The actual DATA of a checkbox that changes, is the state of the checkbox. If you add a "value" attribute to a textarea, for example, `val()` still returns the contents of the textarea, which is logical. The behavior is inconsistent. – Jamie Treworgy Apr 11 '11 at 12:43
  • @jamietre See the other answers, they are plenty of other uses where a checkbox HAS to have a value – Capsule Apr 11 '11 at 12:46
  • @jamietre the `value` of the `textarea` is the text it wraps, while the value of the checkbox lies in its attribute. – S L Apr 11 '11 at 12:47
  • -1 because it doesn't explain why values are useful in checkboxes and why val() shouldn't return true or false based on the checked or not state. – Capsule Apr 11 '11 at 12:48
  • @Capsule it's because the `val()` returns it's value stored in it. Of course what value you expect from a checkbox when you post. And i think `checked` and `value` are different properties. – S L Apr 11 '11 at 12:50
  • What I'm still not getting is why this is a good design decision for jQuery. I understand (now) the purpose of value attribute in checkboxes. But jQuery is an abstraction of javascript. Wouldn't it be more useful to return the true/false state of a checkbox? You can always use attr('value') if that's all you want. – Jamie Treworgy Apr 11 '11 at 12:54
  • @experimentX your second and last examples are wrong because the value attribute cannot be omitted when input type is checkbox or radio, see http://www.w3.org/TR/html4/interact/forms.html#h-17.4 So OK you might get "on" when there's no value but your code is invalid, hence jQuery trying to get back on tracks and sending a "on" default value. – Capsule Apr 11 '11 at 13:33
3

If you pass an array to val function, it will set the checkbox as checked if the checkbox's value matches the value in the array. Source: http://api.jquery.com/val/#val-value

<input id="checkbox" type="checkbox" value="remember">    

$("#checkbox").val(["remember"]);
zhopon
  • 87
  • 1
  • 1
    I feel the same as @Jamie Treworgy: default values of true or false would have made infinitely more sense. – Suncat2000 Sep 01 '17 at 17:36
2

Checkbox has value just like text box and this value is being sent to the server when the form is submitted only if the checkbox was selected at the time of submission.

Unlike text box, checkbox has default value which is on - this is sent to the server when the checkbox is selected but has no value of its own, so that the processing code can know it was selected.

So the .val() method is working just fine, returning the value of the element.

You're correct that jQuery is missing simple way to see if a specific checkbox/radio button is selected, something like $("#mycheckbox").checked() but that's what we have plugins for. :)

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
1

A checkbox is not always alone and its value is passed when submitting the form (otherwise, the name/value is not passed at all).

It's very useful when making arrays out of checkboxes, you can use name="test[]" as their name, and set different values in each. When parsing the submitted result, you end up with an array containing all the checked values

Capsule
  • 6,118
  • 1
  • 20
  • 27
0

You can do some surgery to jquerys val function to act like that. Return true or false whether theres no value attr.

(function (){
    var jval = $.fn.val
    function superval(value){
        if (value === undefined){
            if (this.is("input") && this.attr("type") == "checkbox"){
                if (this.attr("value")===undefined){
                    return this[0].checked
                }
            }
            return jval.call(this)
        } else {
            return jval.call(this, value)
        }
    }
    $.fn.val = superval
})()

console.log($('<input type="checkbox"/>').val()); // false
console.log($('<input type="checkbox" checked="whatever"/>').val()); // true
console.log($('<input type="checkbox" checked="whatever" value="yes"/>').val()); // yes
console.log($('<input type="text" value="heya"/>').val()); // heya
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Mackraken
  • 495
  • 4
  • 5
-1

You may consider using hidden input, containing value you want to retreive, along with checkbox, which will change input's value on "input" and "change" events with any value you want.

something
 .append( $("<INPUT/>")
   .prop("type", "hidden")
   .addClass("mycheckboxvalue")
   .val("initial value")
 )
 .append( $("<INPUT/>")
   .prop("type", "checkbox")
   .prop("checked", initial_state)
   .on("input change", function() {
     $(".mycheckboxvalue").val(
       $(this).is(":checked")?
         "checked value":
         "unchecked value"
     )
   })
 )
Sergey
  • 344
  • 2
  • 12