jQuery / メソッド / .prop() - DOMプロパティを取得・設定する

jQueryの.prop("名前")は最初の選択要素のDOMプロパティを読み、.prop("名前", 値)は選択したすべての要素に設定します。現在のチェック状態は.prop("checked")、無効状態は.prop("disabled")で扱います。HTMLの属性文字列と、ブラウザーが管理する現在の値を区別します。

現在の状態とHTML属性の違い

DOM(Document Object Model、文書オブジェクトモデル)はHTML文書をノードとオブジェクトで表します。.prop()の仕様で扱うchecked・disabled・selectedIndexはそのオブジェクトのプロパティです。.attr()はHTML属性を読み書きします。同名でも常に現在の状態と同じ意味ではありません。

確認対象 方法 意味
現在チェック中か .prop("checked") 真偽値true/false
既定のチェック状態 .prop("defaultChecked") HTML checked属性に対応する既定値
HTML属性自体 .attr("checked")・getAttribute("checked") クリックだけでは変わらない属性
フォーム部品の値 .val() チェック状態とは別のvalue・選択値

<input type="checkbox" checked="">は初期状態でチェックされています。ユーザーが外すとcheckedはfalseになりますが、defaultCheckedと属性はそのままです。チェックボックスのchecked属性は存在が重要な真偽属性であり、checked="false"も未チェックの意味にはなりません。

.attr("checked")の文字列で現在の状態を判定しません。このchecked=""の例では、3.7.1は"checked"、4.0.0は空文字列""を返しました。空文字列はJavaScriptの条件では偽でも、チェックは有効な場合があります。バージョン依存の文字列比較ではなく.prop("checked")の真偽値を使います。

状態・無効化・イベントを比較する完全な例

全コードをUTF-8のprop-demo.htmlとして保存し、ブラウザーで開きます。コンテンツ配信ネットワーク(CDN)の公式jQueryファイル4.0.0を読むためインターネットが必要ですが、インストールは不要です。操作とConsole例を3.7.1・4.0.0で実行しました。属性表示は両版で同じ値を比較できるネイティブgetAttribute()です。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Read and change DOM properties</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
    button { font: inherit; margin: 4px; max-width: 100%; }
    label { display: block; padding: 12px; border: 1px solid #aab; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Current properties and markup attributes</h1>
  <form id="demo-form">
    <label><input type="checkbox" id="subscribe" name="subscription" value="weekly" checked=""> Weekly subscription</label>
  </form>
  <button type="button" id="toggle">Toggle checked</button>
  <button type="button" id="set">Set unchecked and disabled</button>
  <button type="button" id="enable">Enable</button>
  <button type="button" id="notify">Check and trigger change</button>
  <button type="button" id="reset">Reset</button>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      const $box = $("#subscribe");
      let changes = 0;
      function report() {
        $("#result").text(`checked=${$box.prop("checked")}\ndefaultChecked=${$box.prop("defaultChecked")}\nchecked attribute=${JSON.stringify($box.get(0).getAttribute("checked"))}\ndisabled=${$box.prop("disabled")}\nvalue=${$box.val()}\nchange events=${changes}`);
      }
      $box.on("change", function () { changes++; report(); });
      $("#toggle").on("click", function () { $box.prop("checked", function (index, old) { return !old; }); report(); });
      $("#set").on("click", function () { $box.prop({ checked: false, disabled: true }); report(); });
      $("#enable").on("click", function () { $box.prop("disabled", false); report(); });
      $("#notify").on("click", function () { $box.prop("checked", true).trigger("change"); });
      $("#reset").on("click", function () { $("#demo-form").get(0).reset(); $box.prop("disabled", false); changes = 0; report(); });
      report();
    });
  </script>
</body>
</html>

初期結果です。checked attributeの引用符二つは属性が存在して値が空文字列という意味です。存在しなければgetAttribute()はnullを返します。

checked=true
defaultChecked=true
checked attribute=""
disabled=false
value=weekly
change events=0
  1. Toggle checkedはcheckedだけfalseにし、既定値・属性・valueを保ちます。change eventsは0のままです。
  2. チェックボックスを直接オンにするとchange eventsが1増えます。状態変更とイベント通知を分けて比べます。
  3. Set unchecked and disabledは.prop({ checked: false, disabled: true })で未チェックかつ直接操作できない状態にします。
  4. Enableはdisabledをfalseにしますが、チェックはオンにしません。
  5. Check and trigger changeはcheckedをtrueにし、changeを明示的に発生させて数を増やします。.prop()の設定だけではchange処理は実行されません。
  6. Resetは既定のチェック状態を復元し、disabledを別途falseにしてカウンターを0にします。繰り返しても同じ初期結果です。

フォームのreset()がdisabledも戻すとは仮定しません。例では明示的に解除します。changeのtriggerは登録済みの処理へ通知するもので、物理的なポインター操作全体を再現する意味ではありません。状態変更後に表示だけ更新すればよければreport()のような関数を直接呼べます。

オブジェクト・関数設定と選択位置

複数プロパティはオブジェクトで、要素ごとの値は関数で設定します。関数は集合内で0からのindexと旧値を受け、返り値が新値になります。Reset後、開発者ツールのConsoleで次の完全な部分コードを実行します。一時的な二つのチェックボックスを反転・無効化し、最後に削除します。

const $holder = $('<div><input type="checkbox" checked><input type="checkbox"></div>').appendTo("body");
const $boxes = $holder.find("input");
console.log(`before=${$boxes.map(function () { return this.checked; }).get().join(",")}`);
$boxes.prop("checked", function (index, old) { return !old; });
$boxes.prop({ disabled: true });
console.log(`after=${$boxes.map(function () { return this.checked; }).get().join(",")}`);
console.log(`first getter=${$boxes.prop("checked")}; type=${typeof $boxes.prop("checked")}`);
console.log(`disabled count=${$boxes.filter(":disabled").length}`);
console.log(`empty getter=${typeof $().prop("checked")}`);
$holder.remove();
before=true,false
after=false,true
first getter=false; type=boolean
disabled count=2
empty getter=undefined

取得の.prop("checked")は最初のfalseだけを返しますが、設定は両方に適用されます。各状態は.map()・.each()で個別に読みます。最初が未チェックでも全体が未チェックとは限りません。

selectのselectedIndexもプロパティで、最初のoptionは0です。.val()は選択されたoptionのvalueを読みます。次のConsole例は二番目を選択してindexとvalueを表示し、一時要素を削除します。

const $select = $('<select><option value="a">Alpha</option><option value="b">Beta</option></select>').appendTo("body");
$select.prop("selectedIndex", 1);
console.log(`index=${$select.prop("selectedIndex")}; value=${$select.val()}`);
$select.remove();
index=1; value=b

変更されないように見えるとき

checked・disabledには文字列"false"でなく真偽値falseを渡します。確認環境では.prop("checked", "false")は文字列が真に変換され、チェックがオンになりました。組み込みのchecked・disabledを削除する代わりに.prop("disabled", false)のように状態を明示します。

空の選択ではundefinedです。falseは正常な未チェック状態なので区別します。対象が存在するはずなら選択子、.length、DOM準備の時点を確認します。HTML属性が必要かDOMプロパティが必要かを決め、任意のdata-*属性の操作を現在のチェック状態と混同しません。