[jQuery] attr(‘checked’)で取得したチェックボックスの値が変わらない

Railsのバージョンを3.2.13に上げたら、jQueryのバージョンも上がって1.10.1になってた。
チェックボックスの値は

if($("#ruby").attr('checked')){
	...
}

という感じで取得してたんだけど、うまく動作しなくなってしまった。

チェックボックスにチェックがついていても.attr('checked')undefinedを返している。

そして、よく調べると.attr('checked')は状況によって挙動がことなるので使わない方がよいことがわかった。
かわりに.prop('checked')を使用した方がよい。

.prop()の使用例

.prop()を使ってチェックボックスの値を判定する場合は

if($("#ruby").prop('checked')){
	...
}

チェックをつける場合は

$('#ruby').prop('checked', true);

チェックをはずす場合は

$('#ruby').prop('checked', false);

ドキュメントでは

.prop() | jQuery API Documentation

Attributes vs. Properties

The difference between attributes and properties can be important in specific situations. Before jQuery 1.6, the .attr() method sometimes took property values into account when retrieving some attributes, which could cause inconsistent behavior. As of jQuery 1.6, the .prop() method provides a way to explicitly retrieve property values, while .attr() retrieves attributes.

ドキュメントによると、チェックボックスのON、OFFなどのプロパティを明示的に取得するには.prop()を使いなさいということだ。

下の記事にあるようにv1.6がリリースされたときに.attr(), .prop()が分離されたために、jQueryコミュニティが混乱し、結局v1.6.1で後方互換性を持つように再度修正が行われたとのこと。

jQuery1.6のattr()で困ったら、1.6.1にすればいいみたい。 | Ginpen.com

今回検証した結果からすると、このときの延命的な後方互換性がv1.9.1以降に廃止されたということのようだ。

動作検証

実際に比較的に最近のjQueryのバージョンで動作確認を行った。

  • jQuery: v1.8.3, v1.9.1 v1.10.1
  • ブラウザ: Chrome Mac版 バージョン 27.0.1453.116
  • 取得する値: .attr().prop()、DOMエレメントのcheckedプロパティ

検証には次のようなスクリプトを使用した。jQueryのバージョンとinputタグでチェックボックスのコードを変化させる。それぞれの場合でチェックボックスをON、OFFにしたとき取得値の変化を記録した。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>jQuery検証</title>
<!-- <script src="jquery-1.8.3.min.js"></script> -->
<script src="jquery-1.9.1.min.js"></script>
<!-- <script src="jquery-1.10.1.min.js"></script> -->
</head>
<body>
<script>
$(function(){
  $('#exec').click(function(){
    console.log('v'+$().jquery);
    console.log('attr: '+$('#ruby').attr('checked'));
    console.log('prop: '+$('#ruby').prop('checked'));
    console.log('DOM: '+$('#ruby')[0].checked);
  });
});
</script>

<!-- このチェックボックスのコードを変化させる -->
<input type="checkbox" id="ruby" checked>Ruby

<button id="exec">実行</button>
</body>
</html>

checked属性がない場合

inputタグにchecked属性についての記述をしない場合。

<input type="checkbox" id="ruby">

checked属性がない場合の結果は次の表の通りである。.prop()かDOMプロパティであれば、チェックボックスのON、OFFの状態をそのままBool値で返しているが、.attr()ではバージョンによって挙動が異なっていることがわかる。

v1.8.3 v1.9.1
v1.10.1
v1.8.3 v1.9.1
v1.10.1
v1.8.3 v1.9.1
v1.10.1
チェック .attr() .prop() DOM
OFF undefined undefined false false false false
ON checked undefined true true true true

v1.8.3の.attr()ではチェックボックスの状態によって値が変化し真偽値的には.prop()、DOMプロパティと同じような値となるため、チェックボックスの状態を判定するのにif文などで使用できる。

しかし、v1.9.1およびv1.10.1では、チェックボックスのON、OFFの状態には関係ないものとなっている。

つまり、チェックをつけたり消したりしても、.attr('checked')で取得できる値がundefinedで変化しないということになる。

checked属性がある場合

checked属性の設定は次の2種類を試したが、結果は同じだったのでまとめている。

<input type="checkbox" id="ruby" checked>
もしくは
<input type="checkbox" id="ruby" checked="checked">

checked属性がある場合も同様に、v1.8.3ではチェックボックスの状態の判定に使用できる値を返すが、v1.9.1およびv1.10.1ではchecked値はチェックボックスの状態によって変化せず、どれもcheckedを返す。

v1.8.3 v1.9.1
v1.10.1
v1.8.3 v1.9.1
v1.10.1
v1.8.3 v1.9.1
v1.10.1
チェック .attr() .prop() DOM
OFF undefined checked false false false false
ON checked checked true true true true

checked属性値とは

jQueryのドキュメントによると、checked属性値とはcheckedプロパティとは異なりチェックボックスの初期値(最初にチェックが入っているかどうか)を表すものであり、チェックボックスの状態に変化しないということだ。

.prop() | jQuery API Documentation

Nevertheless, the most important concept to remember about the checked attribute is that it does not correspond to the checked property. The attribute actually corresponds to the defaultChecked property and should be used only to set the initial value of the checkbox. The checked attribute value does not change with the state of the checkbox, while the checked property does.

まとめ

.attr()ではjQueryのバージョンによりchecked属性の有無によって返値が異なる。

一方、.prop()およびDOMのcheckedプロパティではチェックボックスの状態を正確に表している。

jQueryのv1.9.1以降は、checked属性は本来チェックボックスのデフォルト値を設定するものなので、チェックボックスの状態により変化しないということを反映している。

といった理由から、jQueryでチェックボックスの状態を判定する場合は.prop('checked')を使用したほうがよい。

checked属性の本来の意味から考えると、チェックボックスの状態を設定するときも.prop()を使用した方がよいでしょう。

ちなみに、ドキュメントではブラウザ互換性のある方法として.is(":checked")も紹介されている。

Therefore, the cross-browser-compatible way to determine if a checkbox is checked is to use the property:

  • if ( elem.checked )
  • if ( $(elem).prop("checked") )
  • if ( $(elem).is(":checked") )

関連記事

    None Found

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です