JavaScript フォームとフォームコントロールの使い方
以下は JavaScript を使ったフォームの作成方法やフォームコントロールの使い方についての覚書です。
Form オブジェクトを使った要素へのアクセスやそのプロパティ、コントロール(ボタンやテキストフィールド、テキストエリア、チェックボックス、ラジオボタン、セレクトボックス)の基本的な使い方やイベント処理などについてサンプルを交えて解説しています。
関連ページ:
- JavaScript を使ったフォームの検証(入力チェック)
- JavaScript フォームの検証(制約検証 API)
- HTML フォームの設置
- jQuery フォームの操作
- PHP フォーム / アンケート
- コンタクトフォーム(お問い合わせページ)の作り方
作成日:2021年8月4日
フォーム
フォームやその部品(フォームコントロール)を使うとユーザーが入力したり選択した値をサーバーに送信したり、それらの値を JavaScript を使って何らかの処理をすることができます。
以下はテキストフィールドと送信及びリセットボタンのフォームコントロールで構成されたフォームです。
送信ボタンをクリックするか、テキストフィールドにカーソルを置いて return キーを押すとフォームはサーバーに送信され、PHP の処理により入力された値が正しいメールアドレスの形式であれば、フォームの下に入力された文字が出力され表示されます。
以下は上記フォームのコードです。PHP を記述してあるのでファイルの拡張子は .php になっています。
<form name="myForm" method="post"> <div> <label for="email">メールアドレス: </label> <input name="email" id="email" value="" size="20"> </div> <input type="submit" name="send"> <input type="reset" name="clear" value="クリア"> </form> <?php $email = filter_input( INPUT_POST, 'email', FILTER_VALIDATE_EMAIL ); $message = $email ? '入力したメールアドレス:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') : ''; ?> <p><?php echo $message; ?> </p>
HTML
form 要素の action 属性を省略して method 属性に post を指定しているので、このフォームは POST メソッドで自分自身に送信されます。
4行目の input 要素は type 属性を省略しているので type="text" が適用されてテキストフィールドになります。
input 要素の type 属性に submit を指定するとそのフォームの送信ボタンになり、reset を指定するとそのフォームのリセットボタンになります。value 属性を指定するとボタンに表示する文字(デフォルトの「送信」や「リセット」)を変更することができます。
関連ページ: HTML フォームの設置
PHP
POST メソッドの場合、$_POST[ '変数名' ] で送信されたフォーム部品の値を取得することができます。変数名にはフォーム部品の name 属性の値を指定します。この例の場合、 $_POST['email'] でテキストフィールドに入力された値を受け取ることができます。
上記の例では filter_input() という PHP 関数を使って入力された値が正しいメールアドレスの形式の場合のみ変数 $email に値を格納し、未入力や形式が正しくない場合は $email には false が代入されます。filter_input() の第2パラメータには取得する変数の名前(name 属性の値)を指定しています。
また、変数 $email には filter_input() により正しい形式のメールアドレスが格納されますが、ユーザーのデータをブラウザに出力する際は、原則として全てのデータを出力時に htmlspecialchars() でエスケープ処理します。
PHP を使ったフォームの操作や検証などについては以下を御覧ください。
関連ページ:PHP フォーム
JavaScript を追加
以下は JavaScript を使って、送信ボタンをクリックした際にテキストフィールドに入力された値を確認して何も入力されていない場合はアラートを表示して送信を中止する例です。
入力された値が空の場合は送信しないようにするには、HTML5 のフォームの検証機能の required 属性を使うこともできます(詳細:JavaScript フォームの検証)。
この例ではフォーム要素の取得に document.forms を使っていますが、querySelector() などの DOM のメソッドを使うこともできます。
また、以下では DOMContentLoaded イベントを使って DOM ツリーの構築(解析)が完了した時点で実行するようにしていますが、</body> の直前で JavaScript を記述したり読み込む場合は省略しても大丈夫な場合が多いです(JavaScript の記述位置)。
<form name="myForm" method="post"> <div> <label for="email">メールアドレス: </label> <input name="email" id="email" value="" size="20"> </div> <input type="submit" name="send"> <input type="reset" name="clear" value="クリア"> </form> <?php $email = filter_input( INPUT_POST, 'email', FILTER_VALIDATE_EMAIL ); $message = $email ? '入力したメールアドレス:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') : ''; ?> <p class="output"><?php echo $message; ?> </p> <script> //DOM ツリーが構築されたら実行するように DOMContentLoaded イベントにリスナーを登録 document.addEventListener('DOMContentLoaded', () => { //フォーム要素を取得 const myform = document.forms.myForm; //ユーザー名を入力する name 属性の値が email の input 要素を取得 const email = myform.email; //フォームに submit イベントのイベントリスナーを登録 myForm.addEventListener('submit', (e) => { //テキストフィールドの値が空の場合 if(email.value == '') { alert('メールアドレスをご入力ください。'); //デフォルトの動作(送信)を中止 e.preventDefault(); } }); }); </script>
複数のフォーム
同じページに複数のフォームを配置する場合、それぞれの form 要素に一意の(重複しない) name 属性や id 属性を指定します。
このページの例では、form 要素の name 属性は同じ値(myForm)になっていますが、同じページに複数のフォームを配置する場合は form 要素に異なる name 属性の値を指定します。
フォーム部品だけを利用
form 要素を使わずに、フォーム部品(フォームコントロール)だけを利用することもできます。
以下はラジオボタンを選択すると、その value 属性の値を id="foo" の div 要素の背景色に設定する例です(詳細:ラジオボタン)。
<div id="foo">フォームサンプル</div> <div> <input type="radio" name="color" value="blue">青 <input type="radio" name="color" value="green">緑 <input type="radio" name="color" value="red">赤 <input type="radio" name="color" value="#666">グレー </div> <script> window.addEventListener('DOMContentLoaded', () => { //id が foo の div 要素を取得 const foo = document.getElementById('foo'); //それぞれのラジオボタンにイベントリスナーを設定 document.getElementsByName('color').forEach( elem => { elem.addEventListener('change', e => { //div 要素の背景色を選択されたラジオボタンの値に foo.style.setProperty('background-color', e.target.value); }); }); }); </script>
name 属性での注意
ハイフンは使わない方が無難
HTML では name 属性の値にハイフンを使用することはできますが、スクリプト上で直接ハイフンを記述すると、マイナス記号として解釈されるのでフォーム要素やフォームコントロールの name 属性にはハイフンを使わない方が無難です。
例えば、以下のように form 要素の name 属性にハイフンを使った場合、document.forms のプロパティとしてフォームの name 属性の値でアクセスしようとすると7行目の「my-form」は「my」「-」「form」と解釈され、エラーになります。
<form name="my-form" method="post"> ・・・中略・・・ </form> <script> //フォーム要素を取得しようとするがエラーになる const myform = document.forms.my-form; //エラー:Uncaught ReferenceError: form is not defined //document.forms.my と - と form </script>
以下のようにブラケット構文や HTMLCollection の namedItem() メソッド、または querySelector() などを使えばアクセスできますが、ハイフンはドット記法のプロパティでは使えないので可能であれば使わないほうが無難だと思います。
<form name="my-form" method="post"> ・・・中略・・・ </form> <script> //ブラケット構文を使う const myform = document.forms['my-form']; //namedItem() メソッドを使う //const myform = document.forms.namedItem("my-form"); //querySelector() でアクセス //const myform = document.querySelector('[name="my-form"]'); //getElementsByNamer() でアクセス //const myform = document.getElementsByName("my-form")[0]; </script>
name 属性や id 属性の値に submit や reset などのメソッド名を使わない
フォームコントロール (送信ボタンやリセットボタン等)の name 属性か id 属性の値に "submit" または "reset" が指定されている場合、フォームの submit() メソッドや reset() メソッドが機能しなくなる場合があります。
以下は MDN/HTMLFormElement.submit からの抜粋です。
もしフォームコントロール (送信ボタン等) の name 属性か id 属性の属性値に "submit" が設定されていた場合、フォームの submit メソッドはマスキングされてしまいます。
以下の場合、ボタンをクリックすると7行目のボタン要素(document.myForm.submit)のイベントの登録は問題ありませんが、11行目の document.myForm.submit() が「 document.myForm.submit は関数ではありません」というエラーになります。
<form name="myForm"> <input type="text" name="myText"> <button name="submit" type="button">送信</button> </form> <script> document.myForm.submit.addEventListener('click', () => { alert(document.myForm.myText.value); //submit() メソッドで送信しようとするが以下のエラーになります //Uncaught TypeError: document.myForm.submit is not a function document.myForm.submit(); //送信できない }); </script>
上記の場合、name 属性によるフォームのプロパティ document.myForm.submit は取得できますが、これと同じ名前のメソッド document.myForm.submit() は機能しません。
上記コードの submit の部分を全て reset に入れ替えても同じ現象(エラー)になってしまいます。
※1 但し、上記コードのボタンの type="button" を削除するか、type="submit" に変更した場合、エラーにはならずフォームは送信されますが、これは11行目の submit() メソッドによる送信ではなく、送信ボタンをクリックすることによる送信機能になります。
※2 上記コードの場合、テキストフィールドにフォーカスして return キーを押せばフォームは送信されてしまいます。
以下のようにボタン要素に id を付与して document.getElementById() で取得しても内部的には document.myForm.submit というプロパティが作成されているので同じくエラーになります。name="submit" を削除すれば機能します。
<form name="myForm"> <input type="text" name="myText"> <button id="btn" name="submit" type="button">送信</button> </form> <script> // id で要素を取得 document.getElementById('btn').addEventListener('click', () => { alert(document.myForm.myText.value); //Uncaught TypeError: document.myForm.submit is not a function document.myForm.submit(); //送信できない }); </script>
プロパティ(属性)名を使っても問題が発生する可能性があります。
メソッド名やプロパティ名だけでなく、イベント名や関数名と同じ名前を name 属性や id 属性の値に指定すると混乱しやすいので避けた方が良いかと思います。
同様に、変数名にもメソッドやプロパティ名、イベント名と同じ名前を使わない方が無難かも知れません。
name="name"
名前を入力するテキストフィールドの name 属性の値に「name」を指定することは良くあり通常は問題ありませんが、フォームコントロールの form プロパティを使ってそのコントロールの所属する form 要素を参照してその name 属性の値を取得しようとすると期待通りにはなりません(このような使い方をすることはあまりないと思うので気にしなくても大丈夫ですが)。
以下では name 属性の値が name の要素を取得して変数 myInput に代入して、myInput.form でその所属する form 要素の属性を出力しています。
myInput.form.name では所属する form 要素の name 属性の値(myForm)が取得できそうですが、実際には myInput.form の name プロパティ、つまり form 要素(myInput.form)内の「name 属性の値が name の要素」を取得します。
フォーム内のコントロールに name 属性を設定すると、そのフォームのプロパティとして(その値のプロパティが)生成されます。この場合、getAttribute() を使えば form 要素の name 属性を取得できます
<form name="myForm" method="post"> <input type="text" name="name" size="35"> <button type="submit" name="send">Submit</button> </form> <script> //name 属性の値が name の要素 const myInput = document.querySelector('input[name="name"]') ; //form プロパティでその要素のフォームを参照しその method 属性の値を出力 console.log(myInput.form.method); //post //同様にフォームの name 属性の値を出力しようとするが「name 属性の値が name の要素」を参照 console.log(myInput.form.name); //<input type="text" name="name" size="35"> //myInput と myInput.form.name が同一であれば Equal と出力 if(myInput === myInput.form.name) console.log('Equal'); //Equal //getAttribute() を使えば name 属性を取得できる console.log(myInput.form.getAttribute('name')); //myForm </script>
JavaScript の記述位置
JavaScript を <head> 内に記述するなど、操作対象の HTML の前に記述する場合などでは、DOM ツリーの構築(解析)が完了した時点で処理を実行するように、DOMContentLoaded などのイベントを使って処理を記述する必要があります。
<head> <script> //DOM ツリーが構築されたら実行 ※画像やスタイルシートの読み込み前 document.addEventListener('DOMContentLoaded', function(){ document.getElementById('sample').style.setProperty('color', 'blue'); }); </script> </head> <body> <p id="sample">Sample</p> </body>
load イベントは、画像やスタイルシートなどを含むページ全体が読み込まれたときに実行する必要がある場合に使用します。
JavaScript の記述や読み込みは body の閉じタグ </body> の直前に記述すれば、ほとんどの場合は問題ないと思いますが、但しその時点で DOM のレンダリングの完了が保証されているわけではないので、処理内容や必要に応じて DOMContentLoaded などの DOM を操作する際に利用できるイベントを使って処理を記述します(関連項目:実行タイミング)。
※ 以降では DOMContentLoaded イベント登録の記述はしていないので必要に応じて追加します。
イベントリスナー
イベントの設定方法には以下のようなものがあります。
- onevent ハンドラー(onclick、onfocus、onsubmit など)を使う方法
- addEventListener() を使う方法
addEventListener() を使う方法は、IE9 未満には対応していませんが、同じ要素に複数のイベントハンドラーを登録できるなどのメリットがあるので、以降では主に addEventListener() を使ってイベントを設定しています。
以下は onclick ハンドラーを使ってボタンをクリックしたらアラートを表示する例です。
13行目のイベントハンドラ関数の設定では関数そのもの(関数名の後に括弧を付けない)を指定します。sayHello() と括弧を付けてしまうと関数を呼び出した結果を代入することになってしまいます。
<input type="button" id="hello" value="Click Here"> <script> //ボタンの要素(input 要素) const hello_btn = document.getElementById("hello"); //イベントハンドラの関数の定義 function sayHello() { alert("Hello"); }; //ボタンの要素の onclick 属性にイベントハンドラの関数を設定 hello_btn.onclick = sayHello; // 関数を別途定義せず無名関数を使って設定する場合 /* hello_btn.onclick = function(){ alert('Hello'); }; */ </script>
以下はボタンをクリックすると、表示されているカウントを増やしていく例で addEventListener() を使って設定しています。
ボタン要素に click イベントのリスナー関数を addEventListener() を使って登録しています。
<button id="btn">Count Up : <span>0</span></button> <script> //イベントを登録するボタン要素 const btn = document.getElementById("btn"); //カウントを表示する span 要素 const count_out = btn.getElementsByTagName('span')[0]; //カウント let count = 0; //イベントが発生したときに呼び出されるリスナー関数 const countUp = () => { count++; count_out.textContent = count; }; //ボタン要素に click イベントのリスナーを登録 btn.addEventListener('click', countUp); </script>
上記の例ではリスナー関数を別途定義していますが、以下のように無名関数を使うこともできます。
//イベントを登録するボタン要素 const btn = document.getElementById("btn"); //カウントを表示するを span 要素 const count_out = btn.getElementsByTagName('span')[0]; //カウント let count = 0; //ボタン要素に click イベントのリスナーを無名関数を使って登録 btn.addEventListener('click', () => { count++; count_out.textContent = count; });
以降の例では無名関数を使うことが多いですが、無名関数を使って登録するとリスナー関数に名前がないため removeEventListener() を使ってイベントリスナーを削除することができなかったり、ループで関数を呼び出す際に繰り返しが多くなると効率的ではなくなるなどのデメリットもあります。
アロー関数
アロー関数と function() を使った関数定義では this の参照先が異なるため、addEventListener() のリスナー関数の定義でアロー関数を使う場合は、this の代わりに Event オブジェクトのプロパティ(currentTarget や target)を使います。
以下は input 要素の値(テキストフィールドに入力された値)が変化するたびに input イベントを使って値を span 要素に出力する例です。
出力:
<input type="text" id="textInput" size="40"> <p>出力:<span id="textOut"></span></p> <script> //テキストフィールドの id 属性が textInput を取得(input 要素) const textInput = document.getElementById('textInput'); //id 属性が textOut の span 要素を取得(出力先) const textOut = document.getElementById('textOut'); //テキストフィールドに input イベントを登録 textInput.addEventListener('input', (e) => { //出力先の textContent にイベントが発生している要素(e.currentTarget)の値を設定 textOut.textContent = e.currentTarget.value; //または textOut.textContent = e.target.value; でもこの例の場合は同じ }); </script>
以下のように記述すると、textInput を this で参照できない(this は外側のスコープを探索する)ため何も出力されません。
textInput.addEventListener('input', () => { //textInput を this で参照できないため何も出力され textOut.textContent = this.value; //NG });
アロー関数の代わりに function() を使えば、this キーワードはリスナが登録されたオブジェクトを参照するので同様の結果を得られます。
textInput.addEventListener('input', function() { textOut.textContent = this.value; //OK });
関連項目:
Form オブジェクト
Document オブジェクトにはドキュメントに現れるフォームや画像、リンクなどのオブジェクトの配列を値として持つプロパティがあり、その中の1つ forms プロパティにはそのドキュメント内の各フォーム要素に対応するオブジェクト(Form オブジェクト)が格納されています。
JavaScript では Form オブジェクトを使ってフォームの操作(処理)を行うことができます。
例えば、そのページ(ドキュメント)の最初のフォーム要素には、document.forms[0](document オブジェクトの forms プロパティのインデックス 0 の要素)でアクセスすることができます。
通常の要素のように、フォームやフォームコントロールの要素には getElementById や querySelectorAll などの DOM のメソッドを使ってアクセスできますが、Document の forms プロパティ(document.forms)を使うと簡単にアクセスすることができます。
document.forms
document.forms はそのページ(ドキュメント内)の全てのフォーム要素に対応するオブジェクトが格納されている配列のようなオブジェクト(HTMLCollection)です。
document.forms に含まれるそれぞれの要素は、単一の form 要素を表す Form オブジェクト(HTMLFormElement)です。
Form オブジェクトへのアクセス
document.forms を使って Form オブジェクトにアクセスする方法はいろいろあります。以下のようなフォームがある場合、
<form name="myForm"> <input type="text" name="inputText"> <input type="submit" name="send"> </form>
form 要素に対応する Form オブジェクト(HTMLFormElement)には以下の方法でアクセスすることができます。
document.forms[0] //フォームのドキュメント中の順序(インデックス番号)で参照 document.forms["myForm"] //配列の添字に name 属性を指定して参照(ブラケット構文) document.forms.myForm //プロパティとしてフォームの name 属性でアクセス(ドット記法) document.forms.namedItem("myForm") //HTMLCollection の namedItem メソッド
上記1行目の document.forms[0] は、そのフォームがドキュメント中の最初(インデックス番号が0)のフォームである場合です。同じページ内にフォームが複数あったり、追加や削除を行うと出現順であるインデックス番号の値が変わる可能性があります。
また、form 要素に name 属性を指定した場合は、ドキュメントオブジェクト自身に name 属性で指定した名前のプロパティができ、対応する Form オブジェクトが格納されるため、以下のように .forms なしで記述しても Form オブジェクト(form 要素)にアクセスすることができます。
document.myForm //一番短い記述
まとめると、以下のような name 属性が設定されたフォームの場合、
<form name="myForm"> ・・・フォームコントロール・・・ </form>
以下の書式で name 属性が設定された form 要素にアクセスすることができます。
書式と例(name 属性が myForm の場合) | 説明 |
---|---|
document.forms[インデックス番号] document.forms[0] |
配列のインデックス番号で参照。インデックス番号は0から始まるドキュメント中のそのフォームの出現順(整数) |
document.forms['name属性の値'] document.forms['myForm'] |
配列の添字に name 属性の値を指定して参照(ブラケット構文) |
document.forms.name属性の値 document.forms.myForm |
Form オブジェクトのプロパティ名(name属性の値)でアクセス(ドット記法) |
document.name属性の値 document.myForm |
ドキュメントオブジェクトのプロパティ名(name属性の値)でアクセス(上記の .forms を省略した書式) |
document.forms.namedItem('name属性の値') document.forms.namedItem('myForm') |
HTMLCollection のメソッド namedItem() でアクセス(.forms は省略可能) |
id 属性
id 属性が設定されていれば、name 属性の代わりに id 属性の値を指定することもできます。但し、name 属性のように「document.id属性の値」ではアクセスできません。
<form id="myForm"> ・・・中略・・・ </form> <script> //以下で上記の id="myForm"の form 要素にアクセス可能 document.forms.myForm document.forms['myForm'] document.getElementById('myForm') //name 属性と異なり、以下ではアクセスできない document.myForm //undefined </script>
実際には id 属性を指定した要素には単に「id 属性の値」(この例では myForm)だけでアクセスできてしまいますが、この方法は非推奨です(id 属性)。
DOM メソッドでアクセス
以下は querySelector() を使って name 属性の値が myForm の form 要素にアクセスする例です。
document.querySelector('form[name="myForm"]')
Form のプロパティ
以下は Form オブジェクト(HTMLFormElement)の主なプロパティです。
プロパティ | 説明 |
---|---|
elements | 【読み取り専用】そのフォーム内に含まれる全てのフォームコントロールを保持する配列のようなオブジェクト(HTMLCollection) |
length | 【読み取り専用】フォーム内のコントロールの数 |
name | フォームの name 属性の値(フォームの名前) |
method | フォームの method 属性の値(フォームの送信に使用する HTTP メソッド) |
target | フォームの target 属性の値(送信して受け取った結果を表示する場所) |
action | フォームの action 属性の値(送信された情報を処理するプログラムの URI) |
encoding | enctype | フォームの enctype 属性の値(サーバーへ送信するのに使用するコンテンツの型) |
acceptCharset | フォームの accept-charset 属性の値(受け付ける文字エンコーディング) |
elements(フォームコントロール)
elements プロパティは form 要素内の全てのフォームコントロールが含まれる配列のようなオブジェクトで、elements プロパティを使ってそのフォーム内のフォームコントロールにアクセスできます。
フォームコントロールとは input 要素や select 要素、textarea 要素などのフォームの部品(コントロール要素)のことで以下の要素が該当します。
- <button>
- <fieldset>
- <input> (type="image" は除く。歴史的な経緯から※)
- <object>
- <output>
- <select>
- <textarea>
※ type="image" の input 要素(画像ボタン)は特別で、elements プロパティには含まれません。
Form オブジェクトへのアクセスと同じように、フォーム内のフォームコントロールにはインデックス番号や name 属性の値、プロパティを使ってアクセスすることができます。
以下のようなフォームがある場合、
<form name="myForm"> <input type="text" name="inputText"> <input type="submit" name="send"> </form>
上記フォームの name 属性が inputText の要素には以下のどれでもアクセスすることができます。
//Form オブジェクトに document.forms[0] でアクセスする場合 document.forms[0].elements[0] //elements[インデックス番号] (最初のコントロール) document.forms[0].elements['inputText'] //elements["name属性の値"] document.forms[0]['inputText'] //forms[0] の連想配列 document.forms[0].inputText //forms[0] のプロパティ //Form オブジェクトに document.forms['myForm'] でアクセスする場合 document.forms['myForm'].elements[0] document.forms['myForm'].elements['inputText'] document.forms['myForm']['inputText'] document.forms['myForm'].inputText //Form オブジェクトに document.forms.myForm でアクセスする場合 document.forms.myForm.elements[0] document.forms.myForm.elements['inputText'] document.forms.myForm['inputText'] document.forms.myForm.inputText //Form オブジェクトに document.myForm でアクセスする場合 document.myForm.elements[0] document.myForm.elements['inputText'] document.myForm['inputText'] document.myForm.inputText
以下は querySelector() を使って name 属性の値が myForm の form 要素の elements プロパティの最初の要素にアクセスする例です。
document.querySelector('form[name="myForm"]').elements[0] //上記のフォームの場合、最初の要素は以下でも同じこと(name 属性が inputText の要素) document.querySelector('form[name="myForm"] input[name="inputText"]')
elements は form 要素内の全てのコントロールが含まれますが、それ以外の要素は含まれません。
例えば、以下のようなフォームの場合、h3 要素や p 要素は elements に含まれません。
<form name="myForm"> <h3>My Form</h3> <p>Please fill out the form below.</p> <input type="text" name="name"> <input type="email" name="email"> <button type="submit" name="send">送信</button> <button type="reset" name="clear">リセット</button> </form>
Form オブジェクトのプロパティ length にはフォーム内のコントロールの数が格納されています。その値は elements (フォーム内のコントロール)の要素数(elements.length)と同じです。
コントロールの最後の要素のインデックスは length-1 になります。
各要素のプロパティや属性は、その要素にアクセスして要素オブジェクト(Element)のプロパティや属性から取得することができます(関連項目:要素の操作)。
elements は配列のようなオブジェクト(HTMLCollection)なので for...of 文が使えます。
//name 属性が myForm の Form オブジェクト const myForm = document.myForm; // または const myForm = document.forms.myForm; // 上記 Form オブジェクトの elements (フォーム内のコントロール) const myElements = myForm.elements; //Form オブジェクトのプロパティ length console.log(myForm.length); //4 //elements (フォーム内のコントロール)の要素数 console.log(myElements.length); //4 //elements (フォーム内のコントロール)の最後の要素 console.log(myElements[myElements.length-1].type); //reset //elements (フォーム内のコントロール)の最後の要素(上記と同じこと) console.log(myElements[myForm.length-1].type); //reset //for 文で各コントロールの name 属性の値を出力 for(let i=0; i< myElements.length; i++) { console.log(myElements[i].name); } //for 文の出力結果 /* name email send clear */ // for of が使えるので以下でも同じ for (let elem of myElements) { console.log(elem.name); }
同じ値の name 属性
ラジオボタンやチェックボックスのように複数の選択肢を設定する要素では、name 属性に同じ値を設定してそれらを関連付けする必要があります。
そのため、複数の同じ値の name 属性の要素があるラジオボタンやチェックボックスでは elements["name属性の値"] は配列となっているので、name 属性を使ってアクセスする場合は elements["name属性の値"][インデックス] のようにインデックスを使って個々の要素にアクセスします。
但し、1つだけのチェックボックスの場合など、同じ値の name 属性の要素が1つだけの場合は配列にはなっていません。
※正確には配列ではなく、elements プロパティ同様、配列のようなオブジェクト(NodeList )です。
以下の場合、elements['color'] は配列になっています。.color プロパティも同様に配列です。
<form name="myForm"> <input type="text" name="name"> <input type="checkbox" name="color" value="blue">青 <input type="checkbox" name="color" value="green">緑 <input type="checkbox" name="color" value="yellow">黄 </form> <script> /*以下は最初のチェックボックス要素の value 属性の値を取得しています。*/ //elements['color'] の最初の要素 let colorValue = document.myForm.elements['color'][0].value; console.log(colorValue); //blue //.color プロパティの最初の要素 colorValue= document.myForm.color[0].value; console.log(colorValue); //blue //.elements プロパティの2番目の要素(1番目はテキストフィールド) colorValue = document.myForm.elements[1].value; console.log(colorValue); //blue /*以下は全てのチェックボックス要素の value 属性の値を取得して出力しています。*/ //colors は全てのチェックボックス要素が格納された配列 const colors = document.myForm.elements.color; // 以下と同じこと //const colors = document.myForm.elements['color']; //配列の要素をループ for(let i=0; i<colors.length; i++) { //各要素のインデックスと値をコンソールに出力 console.log( i + ' : ' + colors[i].value); } /* 0 : blue 1 : green 2 : yellow */ </script>
同じ値の name 属性を設定する
ラジオボタンやチェックボックス以外でも、name 属性に同じ値を設定すれば、elements["name属性の値"] は配列(のようなオブジェクト)になります。
例えば、以下のように複数のメールアドレスを入力するテキストフィールドを作成し、同じ値(この例では emails)の name 属性を設定することができます。
<form name="myForm"> <div> <label for="emails1">E-mail: </label> <input type="text" name="emails" id="emails1" size="30"> </div> <div> <label for="emails2">E-mail: </label> <input type="text" name="emails" id="emails2" size="30"> </div> <div> <label for="emails3">E-mail: </label> <input type="text" name="emails" id="emails3" size="30"> </div> <input type="button" name="check" value="Check"> <input type="reset" value="Reset"> </form>
上記の場合、name 属性が emails の全ての要素(配列のようなオブジェクト)は document.myForm.elements.emails または document.myForm.elements['emails'] で取得できます。
以下ではボタンの要素に addEventListener を使ってクリック時のイベントリスナーを登録し、クリックされたら各テキストフィールドのインデックス番号とに入力されている値をコンソールに出力するようにしています。
<script> //emails は name 属性が emails の全ての要素が格納された配列 const emails = document.myForm.elements.emails; // または let emails = document.myForm.elements['emails']; //name 属性が check の要素(ボタンの要素) const checkButton = document.myForm.elements.check; //ボタンの要素にクリックイベントを登録 checkButton.addEventListener('click', function() { //配列の要素をループ for(let i=0; i<emails.length; i++) { //各要素のインデックスと値をコンソールに出力 console.log( i + ' : ' + emails[i].value); } }) //3つのテキストフィールドに値を入力してボタンをクリックした場合の出力例 /* 0 : foo@example.com 1 : bar@example.com 2 : baz@example.com */ </script>
fieldset 要素
フォーム内の複数のコントロールをグループ化する fieldset 要素もフォームコントロールの1つです。
fieldset(HTMLFieldSetElement)では Form オブジェクト同様、elements プロパティを使うことができます。
以下は name 属性の値が require_field の fieldset 要素の elements プロパティを使って name 属性の値が email の input 要素にアクセスしてその属性(size)の値をコンソールに出力しています。
<form name="myForm"> <fieldset name="require_field"> <legend>Require Field</legend> <div> <label for="inputName">Name: </label><br> <input type="text" name="inputName" id="inputName" value="" size="20"> </div> <div> <label for="email">E-mail: </label><br> <input type="email" name="email" id="email" value="" size="30"> </div> </fieldset> <div> <button type="submit" name="send">Submit</button> </div> </form> <script> //name 属性の値が require_field の fieldset 要素 const fieldset = document.myForm.elements.require_field; //fieldset 要素の elements プロパティで name 属性の値が email の要素にアクセス console.log(fieldset.elements.email.size); //30 //form 要素の elements プロパティで name 属性の値が email の要素にアクセス(同じこと) console.log( document.forms['myForm'].elements.email.size); //30 //fieldset 要素の form プロパティで所属する form 要素にアクセス console.log(fieldset.form.name); //myForm </script>
fieldset の利用
Form オブジェクトの elements プロパティはそのフォーム内のボタンなどを含む全てのフォームコントロールが含まれています。
そのため、例えば for 文でループして特定の要素の値を取得したい場合などでは、ボタン要素などを除外する必要があります。
fieldset 要素も form 要素と同じように elements プロパティを持っているので、fieldset 要素で特定のコントロールをグループ化することでそのグループだけに対して処理することができます。
または、同じ値の name 属性を設定することでそれらを配列(のようなオブジェクト)として処理することもできます。
以下は3つのテキストフィールドを fieldset 要素でグループ化しています。legend や label 要素はフォームコントロールではないので elements プロパティには含まれません。
<form name="myForm"> <fieldset name="required_field"><!-- fieldset ここから --> <legend>Required Field</legend> <div> <label for="name2">Name: </label> <input type="text" name="name" id="name2" value="" size="30"> </div> <div> <label for="email2">E-mail: </label> <input type="text" name="email" id="email2" value="" size="30"> </div> <div> <label for="tel2">TEL: </label> <input type="text" name="tel" id="tel2" value="" size="30"> </div> </fieldset><!-- fieldset ここまで --> <button type="button" name="check">Check</button> <button type="reset" name="clear">Clear</button> </form>
fieldset 要素の elements プロパティには、3つのテキストフィールドが入っているので、それをループしてそれぞれの要素の name プロパティと value プロパティを出力しています。
<script> //name 属性が myForm の form 要素 const myForm = document.myForm; //フォームのボタンにクリックイベントを登録 myForm.check.addEventListener('click', ()=> { //name 属性が myForm の form 要素の fieldset 要素 const fieldset = myForm.elements.required_field; //fieldset 要素の elements プロパティを for 文でループ for(let i=0; i<fieldset.elements.length; i++) { //elements プロパティの各要素の name プロパティと value プロパティを出力 console.log(fieldset.elements[i].name + ': ' + fieldset.elements[i].value); } }); //コンソールへの出力例 /* name: Foo email: foo@exmaple.com tel: 123-456-789 */ </script>
elements は配列のようなオブジェクト(HTMLCollection)なので for...of 文が使えるので上記は以下のように記述することができます。
const myForm = document.myForm; myForm.check.addEventListener('click', ()=> { const fieldset = myForm.elements.required_field; for (let elem of fieldset.elements) { console.log(elem.name + ': ' + elem.value); } });;
フォームを参照
フォームコントロールの form プロパティを使ってそのコントロール要素が所属するフォームを参照することができます。
以下は document.querySelector() で name="inputName" の input 要素を取得して変数 inputName に代入し、input 要素の所属する form 要素を inputName.form で参照しています。
そして form 要素のプロパティ(name 属性や method 属性の値)をコンソールに出力しています。
14行目は input 要素の属する form 要素の send プロパティ(name="send" の input 要素)の value 属性の値を取得しています。
<form name="myForm" action="checkForm.php" method="post"> <input type="text" name="inputName" size="35"> <button type="submit" name="send" value="nameSubmit">Submit</button> </form> <script> //name 属性の値が inputName の要素 const inputName = document.querySelector('input[name="inputName"]') ; //form プロパティでその要素のフォームを参照 console.log(inputName.form.name); //myForm console.log(inputName.form.action); //http://example.com/path/checkForm.php console.log(inputName.form.method); //post //form の send プロパティ(name="send" の input 要素)の value の値 console.log(inputName.form.send.value); //nameSubmit </script>
但し、もし上記の input 要素の name 属性の値を name としてしまうと input 要素の .form.name は form 要素の name 属性の値ではなく、name 属性の値が name の要素(input 要素 = 自分自身)を参照してしまいます。
Form のメソッド
以下は Form オブジェクト(form 要素)の主なメソッドです。
メソッド | 説明 |
---|---|
reset() | フォームを初期状態にリセットします |
submit() | フォームをサーバーへ送信します。HTML5 の検証は行われず、submit イベントも発生しません。 |
reportValidity() | このフォームのコントロールに設定された HTML5 の検証を満たしていれば true を返し、そうでなければ false を返します。 false が返された場合、キャンセル可能な invalid イベントが無効なコントロールそれぞれについて発行されます。 |
requestSubmit() | フォームをサーバーへ送信します。submit() とは異なり、HTML5 の検証も行われ、submit イベントも発生します。 |
submit() メソッド
フォームのメソッド submit() を呼びだすことで、手動でサーバにフォームを送信することができます。
但し、ユーザーが送信ボタンをクリックしたり return キーを押してフォームを送信するのと全く同じではなく、例えば submit イベントは発生しません。
また、submit() メソッドを使ってフォームを送信した場合は HTML5 の検証は行われません。
以下は input 要素に required 属性を指定して入力を必須としているので何も入力せず送信しようとすると、HTML5 の機能で「このフィールドを入力してください」などのメッセージが表示され、送信することができないようにしています。
<form name="myForm"> <input type="text" name="myText" required><!-- required 属性を設定--> <button name="send">送信</button><!-- type を省略しているので type="submit" と同じ--> </form>
しかし、以下のように button に type="button" を指定して通常のボタンにして、click イベントを使って submit() でフォームを送信すると、HTML5 の検証は行われず、何も入力せず送信できてしまいます。また、その際、フォームの submit イベントは発生しません。
<form name="myForm"> <input type="text" name="myText" required><!-- required 属性を設定--> <button name="send" type="button">送信</button> </form> <script> //ボタンに click イベントのイベントリスナーを登録 document.myForm.send.addEventListener('click', () => { //submit() でフォームを送信 document.myForm.submit(); }); //フォームに submit イベントのイベントリスナーを登録 document.myForm.addEventListener('submit', () => { alert('submit'); }); </script>
但し、テキストフィールドにカーソルを置いて何も入力しない状態で、return キーを押せば click イベントは発生せずフォームにより送信が実行されるので HTML5 のフォームの検証が行われます。
また、テキストフィールドに値を入力してフォーカス状態にして return キーを押せば click イベントは発生しませんが、submit イベントは発生するのでアラートが表示されます。
submit() メソッドを使ってフォームを送信する際に、HTML5 の検証を行うには reportValidity() を使って検証が満たされているかをチェックしたり、requestSubmit() を使うなどの方法があります。
reportValidity()
form 要素の reportValidity() メソッドを使うとフォームの子要素のコントロールが設定した HTML5 の検証を満たしているかをチェックすることができます。
reportValidity() はコントロールが制約を満たしていれば true を返すので、以下ではコントロールが検証をパスしている場合にのみ submit() でフォームを送信するようにしています。
また、reportValidity() はコントロールが制約を満たしていない場合は false を返し、制約を満たしていない要素で invalid イベントが発行され、ユーザー(ブラウザ)にエラーメッセージを表示します。
そのため、何も入力されていない状態でボタンをクリックすると、「このフィールドを入力してください」などのエラーメッセージが表示されますが、 submit() は実行されずフォームは送信されません。
値が何か入力されていれば検証を満たしているので、ボタンをクリックするとフォームが送信されますが、ボタンのクリックでは submit イベントは発生しないのでアラートは表示されません。
カーソルを入力フィールドに置いて、値が何か入力された状態で return キーを押すと、フォームは送信され submit イベントが発生してアラートが表示されます。
<form name="myForm"> <input type="text" name="myText" required><!-- required 属性を設定--> <button name="send" type="button">送信</button> </form> <script> //ボタンに click イベントのイベントリスナーを登録 document.myForm.send.addEventListener('click', () => { //コントロールが検証を満たしていれば submit() でフォームを送信 if(document.myForm.reportValidity()) { document.myForm.submit(); } }); //フォームに submit イベントのイベントリスナーを登録 document.myForm.addEventListener('submit', () => { alert('submit'); }); </script>
requestSubmit()
requestSubmit() を使うと、送信ボタンをクリックしてフォームを送信するのと同様の送信を行うことができます。
以下の場合、ボタンをクリックすると HTML5 の検証が行われ、submit イベントも発生するのでアラートが表示されます。
<form name="myForm"> <input type="text" name="myText" required><!-- required 属性を設定--> <button name="send" type="button">送信</button> </form> <script> //ボタンに click イベントのイベントリスナーを登録 document.myForm.send.addEventListener('click', () => { // requestSubmit() でフォームを送信(送信ボタンのをクリックするのと同じ) document.myForm.requestSubmit(); }); //フォームに submit イベントのイベントリスナーを登録 document.myForm.addEventListener('submit', () => { alert('submit'); }); </script>
submit() は単にフォームを送信するだけです。 一方、requestSubmit() は、送信ボタンがクリックされたかのように機能し、HTML5 の検証が設定sれていればフォームのコンテンツが検証され、検証が成功した場合にのみフォームが送信されます。 フォームが送信されると、submit イベントが発生します。
submit() の使用例
submit() は例えば、フォームを動的に作成してそのフォームを送信する場合などに使えます。
以下は createElement() メソッドを使ってフォームを作成し、そのフォームを submit() メソッドで action 属性で指定した URL に送信する例です。
ボタンをクリックすると GET メソッドなので ?q=JavaScript のクエリが action 属性で指定した送信先の Google 検索の URL に追加され、「JavaScript」についての Google の検索結果が別ウィンドウで表示されます。
<button id="searchBtn">JavaScript について検索</button> <script> //form 要素を作成 const searchForm = document.createElement('form'); //form 要素の action 属性を設定(送信先を Google 検索へ) searchForm.action = 'https://google.com/search'; //form 要素の method 属性に GET を設定(URL に ? 区切りで値を追加して送信) searchForm.method = 'GET'; //form 要素の target 属性(結果を表示する場所)に _blank を設定 searchForm.target = '_blank'; //form 要素に送信する input 要素を追加(GET メソッドに q=JavaScript が追加される) searchForm.innerHTML = '<input name="q" value="JavaScript">'; //form 要素を非表示に searchForm.style.setProperty('display', 'none'); //body に生成した form 要素を追加 document.body.append(searchForm); //既存のボタンに click イベントのイベントリスナーを登録 document.getElementById('searchBtn').addEventListener('click', () => { //ボタンをクリックしたら作成したフォームを送信 searchForm.submit(); }); </script>
イベント
以下は Form オブジェクト(form 要素)の主なイベントです。
イベント | 説明 |
---|---|
reset | フォームがリセットされたときに発生します。 |
submit | フォームが送信されたときに発生します。 |
フォームは以下の方法で送信されます。
- フォームの送信ボタン(type="submit")をクリック
- フォームの入力欄をクリックして return キーを押す
- JavaScript でフォームのメソッド submit() または requestSubmit() を呼び出す(※)
※ submit() メソッドを使った送信では submit イベントは発生しません。
以下は addEventListener を使って submit イベントと reset イベントを登録する例です。
フォームが送信される際に発生する submit イベントではテキストフィールドに値が入力されているかをチェックし、入力されていない場合はアラートを表示し、Event オブジェクト(e)の preventDefault() でデフォルトの動作(送信)をキャンセルします。デフォルトの動作を停止しないとフォームは送信されてしまいます。
addEventListener のリスナー関数には Event オブジェクト(この例では e として受け取っています)が引数として渡されます。
リセットボタンをクリックされた際に発生する reset イベントでは、confirm ダイアログを表示してユーザーがキャンセルを選択した場合は、デフォルトの動作のリセットを停止します。
<form name="myForm"> <input type="text" name="name" value="" size="20"> <input type="email" name="email" value="" size="30"> <button type="submit" name="send">送信</button> <button type="reset" name="clear">リセット</button> </form> <script> //フォームを取得 const form = document.myForm; //フォームに submit イベントを登録 form.addEventListener('submit', (e) => { //送信時のテキストフィールド(name="name")の値 const name_val = form.name.value; //送信時のテキストフィールド(name="email")の値 const email_val = form.email.value; //値が未入力の場合はアラートを表示してデフォルトの動作の送信を中止 if(name_val === '' | email_val === ''){ alert('入力は必須です。'); e.preventDefault(); } }); //フォームに reset イベントを登録 form.addEventListener('reset', (e) => { //confirm ダイアログを表示 const response = confirm('値を全てクリアしますか?'); if(!response) { //キャンセルがクリックされたらデフォルトの動作のリセットを中止 e.preventDefault(); } }); </script>
submit イベントと click イベント
通常のフォームの送信(送信ボタンをクリックしたり、フォームの入力欄をクリックして return キーを押す)では、click イベントと submit イベントの両方が発生します。
click イベント → submit イベントの順で発生します。
以下のフォームを送信すると、ボタンをクリックしても入力欄をクリックして return キーを押しても「click」及び「submit」と2回アラートが表示されます。
<form name="myForm"> <input type="text" name="textInput" size="30"> <button type="submit" name="send">送信</button> <button type="reset" name="clear">クリア</button> </form> <script> document.myForm.addEventListener('submit', (e) => { alert(e.type); //submit とアラート表示 e.preventDefault(); //※ }); document.myForm.send.addEventListener('click', (e) => { alert(e.type); //click とアラート表示 }); </script>
(※)この例では実際にフォームが送信されるかどうかは関係がないのと、フォームが送信されるとページの先頭に移動してしまうので、e.preventDefault() でフォームの送信をしないようにしています。
送信時の位置を保持
フォームを送信(submit)すると、 action 属性で指定したファイルが読み込まれ、送信した際の画面の表示位置はリセットされページの先頭が表示されます。
action 属性は指定していない場合は自身のファイルが読み込まれ、ページの先頭に移動します。
以下は submit イベントを使って、フォームの送信先を自分自身にした場合に、送信した際の表示位置を保持してページロード後も同じスクロール位置で表示する例です。
※この場合、PHP が実行できるようにファイルの拡張子を .php にするか、.htaccess ファイルなどを使って拡張子 .html で PHP を実行できるようにする必要があります。
フォームの HTML ではフォームを送信する際の位置の情報(スクロール量)を保存するための type="hidden" を指定した input 要素(隠しフィールド)を用意します。name 属性の値は任意ですが、この例では scroll_top という値を指定しています。
フォームを送信する時点のスクロール量を JavaScript の window.scrollY で取得し、それを隠しフィールド(この例では name 属性が scroll_top の input 要素)の value 属性に設定します。
フォームが送信されていない場合は、PHP の変数 $_REQUEST['scroll_top'] は設定されていないので、value 属性には isset() で判定して、設定されていればその値を、されていれば空文字を設定しています。
フォームが送信されてページが再読み込みされると、PHP の変数 $_REQUEST['scroll_top'] で隠しフィールドに設定したスクロール量が取得できます。この例では GET メソッドと POST メソッドの両方の場合に対応するように、値の取得は「$_REQUEST」スーパーグローバル変数を使用しています。
ページが読み込まれたら、隠しフィールドの値を確認し(値が空でなければ)隠しフィールドの値を使って window.scroll() で元の位置にスクロールします。
この場合、DOM ツリー構築完了後、画像やスタイルシートなどの読み込みが完了したら実行するように DOMContentLoaded ではなく、load イベントを使っています。DOMContentLoaded を使う場合は、window に対して登録すれば良いようです(document に対しての登録では、コンテンツにもよると思いますが、正確なスクロール位置が取得できないようです)。
<form name="myForm" method="post"> <div> <label for="name">名前 </label> <input name="name" id="name" value="" size="20"> </div> <button>送信</button> <!-- 隠しフィールド(垂直方向のスクロール量を value に設定) --> <input type="hidden" name="scroll_top" value="<?php echo isset($_REQUEST['scroll_top']) ? $_REQUEST['scroll_top']: ''; ?>"> </form> <script> //load イベントにリスナーを登録 window.addEventListener('load', () => { //フォームの submit イベント document.myForm.addEventListener('submit', ()=> { //name 属性が scroll_top の要素(隠しフィールド)があれば if(myForm.scroll_top) { //垂直方向のスクロール量を取得 const scrollTop = window.scrollY ; //隠しフィールドの value 属性に現在の垂直方向のスクロール量を設定 myForm.scroll_top.value = scrollTop; } }); //ページが読み込まれて隠しフィールドの値が空でなければ if(myForm.scroll_top.value) { //隠しフィールドの値を使ってスクロール window.scroll(0, myForm.scroll_top.value); } }); </script>
複数のフォームに対応
以下は同じページに複数のフォームがある場合でも、それぞれのフォームを送信するとその位置に表示するようにした例です。
この場合、それぞれの form 要素の name 属性には依存しませんが、隠しフィールドには、同じ name 属性 scroll_top を指定して、value 属性に PHP の変数を記述する必要があります。
<form name="myForm2" method="post"> <div> <label for="name2">名前(2) </label> <input name="name2" id="name2" value="" size="20"> </div> <button>送信</button> <!-- name 属性が scroll_top の隠しフィールドを設定 --> <input type="hidden" name="scroll_top" value="<?php echo isset($_REQUEST['scroll_top']) ? $_REQUEST['scroll_top']: ''; ?>"> </form>
//load イベントにリスナーを登録 window.addEventListener('load', () => { //そのページの全ての form 要素を取得 const forms = document.forms; //垂直方向スクロール量を入れる変数の初期化 let scrollTopValue = ''; //全ての form 要素を for 文で処理 for(let i=0; i<forms.length; i++) { //name 属性が scroll_top の要素がそのフォームにあれば if(forms[i].scroll_top) { //フォームの submit イベントを設定 forms[i].addEventListener('submit', ()=> { //送信時の垂直方向のスクロール量を取得 const scrollTop = window.scrollY ; //隠しフィールドに現在の垂直方向のスクロール量を設定 forms[i].scroll_top.value = scrollTop; }); //隠しフィールドで送信された値(垂直方向スクロール量)を変数に代入 scrollTopValue = forms[i].scroll_top.value ; } } //垂直方向スクロール量が空でなければページが読み込まれたらスクロール if(scrollTopValue) { window.scroll(0, scrollTopValue); } });
フォームコントロール
input 要素や select 要素、textarea 要素、button 要素などのコントロールはフォーム要素内に配置するとフォームの部品として機能しますが、単独でも入力コントロールなどとして使用することができます。
フォーム要素内に配置されたコントロールは Form オブジェクトの elements プロパティを使ってアクセスできますが、単独で配置されたコントロールは getElementById などの DOM のメソッドを使ってアクセスできます。
フォームコントロールで共通して使用できるプロパティとメソッド
フォームコントロールには、それぞれ固有のプロパティ(要素の属性)とメソッドがありますが、以下のプロパティやメソッドは共通して使用することができます。
プロパティ(属性) | 説明 |
---|---|
dsabled | 要素の入力や選択を無効にする属性 |
form | その要素が属するフォーム要素(Form オブジェクト) |
labels | その要素に関連付けられた label 要素のリスト(NodeList)。 |
name | 要素に設定された名前(name 属性の値) |
type | 要素の種類(type 属性の値) |
value | value 属性に設定されている値や入力された値 |
要素 | インターフェース(MDN リンク) |
---|---|
button | HTMLButtonElement |
input(text, radio, checkbox 等) | HTMLInputElement |
textarea | HTMLTextAreaElement |
select | HTMLSelectElement |
fieldset | HTMLFieldsetElement |
HTML 要素共通 | HTMLElement |
値の取得と設定
input 要素や textarea 要素の入力された値の取得や設定は value
プロパティを使用します。
以下の場合、2つ目のコンソールへの出力は入力された値に関わらず常に初期値が出力されます。
<input type="text" id="my-input" value="My Input"> <script> const myTextInput= document.getElementById('my-input'); myTextInput.addEventListener('change', ()=> { console.log(myTextInput.value); // 入力された値が出力される console.log(myTextInput.getAttribute('value')); //常に初期値(My Input)が出力される }) </script>
getAttribute('value') は HTML の value 属性に記述されている値や setAttribute('value') または defaultValue プロパティで設定された値を参照することができます。
value 属性の値と value プロパティは別物と考えるとわかりやすいかもしれません。
入力された値の取得や設定は value プロパティを使い、 HTML の value 属性に記述されている値は getAttribute('value') や setAttribute('value')、または defaultValue プロパティを使います。
テキストフィールド
input 要素の type 属性に text を指定するか type 属性を省略すると、単一行のテキスト入力欄(テキストフィールド)になります。
複数行の文章を入力させる場合は textarea 要素(テキストエリア)を使用します。
<input type="text" name="firstName" size="20" placeholder="First Name">
type 属性に password を指定した input 要素や HTML5 で新たに追加されたフォーム部品の type 属性(email, tel, url, range など)も1行入力欄のテキストフィールドです。
<input type="range" name="myRange" value="30" min="0" max="100" step="5">
必要に応じて value 属性に初期値を設定することができます。
<input name="country" size="20" value="日本"><!--この例では type 属性を省略 -->
テキストフィールドがフォーム内にある場合は、document.forms や elements を使って取得(アクセス)することができます。
以下は document.forms を使って name 属性が myForm の form 要素の name 属性が emailInput の elements プロパティ(input 要素)にアクセスしています。
<form name="myForm"> <div> <label for="emailInput">E-mail: </label> <input type="email" name="emailInput" id="emailInput" value="" size="20"> </div> </form> <script> const emailElem = document.myForm.emailInput; //以下でも同じこと ※ .forms は省略可能 //const emailElem = document.forms.myForm.emailInput; //const emailElem = document.forms['myForm'].emailInput; //const emailElem = document.forms.myForm['emailInput']; //const emailElem = document.forms.myForm.elements['emailInput']; //上記で取得した要素の type 属性をコンソールに出力 console.log(emailElem.type); //email </script>
フォーム内にない場合は(フォーム内にある場合でも)、 DOM のメソッドを使って取得(アクセス)することができます。
<label for="emailInput">E-mail: </label> <input type="email" name="emailInput" id="emailInput" value="" size="20"> <script> const emailElem = document.getElementById('emailInput'); //この例の場合、以下のいずれでも同じ //const emailElem = document.querySelector('input[name="emailInput"]'); //const emailElem = document.getElementsByName('emailInput')[0]; //const emailElem = document.getElementsByTagName('input')[0]; console.log(emailElem.type); //email </script>
値の取得 value
テキストフィールドに入力されている値は value プロパティで取得できます。
HTML の value 属性に設定されている値は、defaultValue プロパティや getAttributes() で取得できます(初期状態では value プロパティと同じ)。
以下は Click と表示されたボタンをクリックするとテキストフィールドに入力された値とその文字数をアラート表示する例です。
文字列の長さ:length
文字列の長さを取得するには String オブジェクトのプロパティ length を使います。但し、空白文字も文字数としてカウントされます。必要に応じて String オブジェクトの trim() メソッドを使って前後の空白を削除します。
<input type="text" id="myText" size="20"> <button type="button" id="btn">Click</button> <script> document.getElementById('btn').addEventListener('click', () => { //value プロパティで値を取得 let myTextValue = document.getElementById('myText').value; //前後の空白を削除(間の空白は削除されない) myTextValue = myTextValue.trim(); //前後の空白を覗いた文字数を length で取得 const myTextLength = myTextValue.length; //値と文字数をアラート表示 alert('入力値: ' + myTextValue + ' 文字数: ' + myTextLength); }); </script>
以下は name="check" のボタン(14行目)をクリックすると、テキストフィールドに入力されている値を取得してコンソールに出力する例です。
<form name="myForm" id="myForm"> <div> <label for="name">Name: </label> <input type="text" name="name" id="name" size="30"> </div> <div> <label for="email">E-mail: </label> <input type="text" name="email" id="email" size="30"> </div> <div> <label for="tel">TEL: </label> <input type="text" name="tel" id="tel" size="30"> </div> <input type="button" name="check" id="check" value="Check"> <input type="reset" value="Reset"> </form>
ボタンの要素に addEventListener を使って click イベントを設定し、それぞれのテキストフィールドに入力されている値をコンソールに出力しています。
この例ではボタンは通常のボタン(type="button")なので、クリックしてもフォームのデータは送信されません。サーバーにデータを送信するには送信ボタン(type="submit")を使います。
フォーム内の要素には document.myForm(または document.forms.myForm)に続けてその要素の name 属性をプロパティとして指定してアクセスすることができ、その値は .value で取得できます。
//name 属性が check のボタン要素にクリックイベントを登録 document.myForm.check.addEventListener('click', ()=> { //name 属性が name のテキストフィールドの値 const name = document.myForm.name.value; //name 属性が email のテキストフィールドの値 const email = document.myForm.email.value; //name 属性が tel のテキストフィールドの値 const tel = document.myForm.tel.value; console.log('名前: ' + name); console.log('メール: ' + email); console.log('電話: ' + tel); }); //コンソールへの出力例 /* 名前: Foo メール: foo@example.com 電話: 123-456-7890 */
上記は以下のように 変数(myForm)に name 属性が myForm の form 要素を取得して、それを基点に書き換えることができます 。
//name 属性が myForm の form 要素 const myForm = document.myForm; // または const myForm = document.forms.myForm; など //name 属性が check のボタン要素にクリックイベントを登録 myForm.check.addEventListener('click', ()=> { //name 属性が name のテキストフィールドの値 const name = myForm.name.value; //name 属性が email のテキストフィールドの値 const email = myForm.email.value; //name 属性が tel のテキストフィールドの値 const tel = myForm.tel.value; console.log('名前: ' + name); console.log('メール: ' + email); console.log('電話: ' + tel); });
以下のように querySelector() を使ってそれぞれの要素にアクセスすることもできます。
//name 属性が myForm の form 要素 const myForm = document.querySelector('form[name="myForm"]'); //上記 form 要素 を基点に name 属性が check の要素(ボタン)を取得 const check_btn = myForm.querySelector('input[name="check"]'); check_btn.addEventListener('click', ()=> { //上記 form 要素 を基点に name name 属性が name の要素を取得 const name = myForm.querySelector('input[name="name"]').value; const email = myForm.querySelector('input[name="email"]').value; const tel = myForm.querySelector('input[name="tel"]').value; console.log('名前: ' + name); console.log('メール: ' + email); console.log('電話: ' + tel); });
また、この例の場合はそれぞれの要素に id 属性を付与してあるので getElementById() を使ってそれぞれの要素にアクセスすることもできます。要素へのアクセス方法は色々とあります(関連項目:要素の取得)。
//id 属性が myForm の要素 const myForm = document.getElementById('myForm'); //id 属性が check の要素 const check_btn = document.getElementById('check'); check_btn.addEventListener('click', ()=> { //getElementById() で要素にアクセスしてその値(.value)を取得 const name = document.getElementById('name').value; const email = document.getElementById('email').value; const tel = document.getElementById('tel').value; console.log('名前: ' + name); console.log('メール: ' + email); console.log('電話: ' + tel); });
エスケープ(サニタイジング)
ユーザなど外部から入力された値を innerHTML を使って挿入(出力)する場合などでは、不正なスクリプトが実行されないように出力する際に値をエスケープ(サニタイジング)するか検証する必要があります。
textContent や innerText を使って値を設定したり、insertAdjacentText() を使って挿入する場合は、値の特殊文字(& < >)はエスケープされるので、外部から入力された値を出力する場合は基本的に textContent や innerText を使うのが良いと思います。
textContent で値を挿入
以下は textContent を使って値を挿入する例です。
Check というボタンをクリックすると入力されている値を name="output" の textarea 要素の textContent に設定して出力します。リセットボタンをクリックするとデフォルトの動作の入力された値をリセットするのに加えて textarea 要素の textContent を空にして出力をクリアします。
<form name="myForm"> <div> <label for="name">Name: </label> <input type="text" name="name" id="name" size="30"> </div> <div> <label for="email">E-mail: </label> <input type="text" name="email" id="email" size="30"> </div> <div> <label for="tel">TEL: </label> <input type="text" name="tel" id="tel" size="30"> </div> <button type="button" name="check">Check</button> <button type="reset" name="clear">Reset</button> <div class="output_div"> <textarea name="output" rows="3" cols="50" readonly></textarea> </div> </form> <script> //name 属性が myForm の form 要素 const myForm = document.myForm; //name="check" のボタンに click イベントのイベントリスナーを登録 myForm.check.addEventListener('click', () => { //name 属性が name のテキストフィールドの値 const name = myForm.name.value; //name 属性が email のテキストフィールドの値 const email = myForm.email.value; //name 属性が tel のテキストフィールドの値 const tel = myForm.tel.value; //テキストエリアに textContent を使って値を挿入(値はエスケープされる) myForm.output.textContent = '名前: ' + name + '\nメール: ' + email + '\n電話: ' + tel; }); //name="clear" のボタン(リセットボタン)に click イベントのイベントリスナーを登録 myForm.clear.addEventListener('click', () => { //出力をクリア myForm.output.textContent = ''; }); </script>
サニタイジング用関数を作成
PHP には、エスケープ処理を行う htmlspecialchars() と言う関数が用意されていますが、JavaScript にはそれに該当する関数はありません。
以下は特殊文字をエスケープして無害化するサニタイジング用の関数 h() の例です。引数に与えられた文字列の中の特殊文字(& " ' < >)をエスケープして返します。サニタイジング(エスケープ処理)
function h(str){ return str.replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/</g, '<') .replace(/>/g, '>'); }
以下は、ボタンをクリックしたらテキストフィールドに入力された値をサニタイズしてテキストエリアに innerHTML を使って挿入して出力する例です。但し、この例の場合は前述の例のように innerHTML の代わりに textContent を使った方が簡単です。
<form name="myForm"> <div> <label for="name">Name: </label> <input type="text" name="name" id="name" size="30"> </div> <div> <label for="email">E-mail: </label> <input type="text" name="email" id="email" size="30"> </div> <div> <label for="tel">TEL: </label> <input type="text" name="tel" id="tel" size="30"> </div> <button type="button" name="check">Check</button> <button type="reset" name="clear">Reset</button> <div class="output_div"> <textarea name="output" rows="3" cols="50" readonly></textarea> </div> </form> <script> //サニタイジング用関数 function h(str){ return str.replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/</g, '<') .replace(/>/g, '>'); } //name 属性が myForm の form 要素 const myForm = document.myForm; //上記 form 要素(myForm)の name 属性が output の要素(テキストエリア) const output = myForm.output; myForm.check.addEventListener('click', ()=> { //name 属性が name のテキストフィールドの値 const name = myForm.name.value; //name 属性が email のテキストフィールドの値 const email = myForm.email.value; //name 属性が tel のテキストフィールドの値 const tel = myForm.tel.value; //テキストエリアの値に h() でエスケープした値を出力 output.innerHTML = '名前: ' + h(name) + '\nメール: ' + h(email) + '\n電話: ' + h(tel); }); myForm.clear.addEventListener('click', ()=> { //出力をクリア output.innerHTML = ''; }); </script>
defaultValue(初期値)
必要に応じてテキストフィールドの value 属性に値を設定して初期値を設定して表示することができます。
value プロパティで取得する値はユーザの入力により変わりますが、value 属性に設定した初期値は defaultValue プロパティで参照することができます。
<form> <input type="text" name="city" value="初期値" size="30"> <button type="reset">Reset</button> </form>
type="reset" のリセットボタンをクリックすると、value 属性に設定した初期値が表示されます。value 属性を設定していない場合や、空の値を設定している場合はクリアされます。
必要であれば、JavaScript から defaultValue プロパティに値を設定して変更することもできます。
<form name="myForm"> <div> City: <input type="text" name="inputCity" value="City Name" size="30"> </div> <input type="button" name="check" value="Check"> <input type="button" name="change" value="Change Default"> <input type="reset" value="Reset"> <input type="button" name="resetDefault" value="Reset Default"> <div class="output_div"> <label for="output">value(入力された値): </label> <textarea name="output" id="output" rows="1" cols="50" readonly></textarea> <label for="output-2">defaultValue(初期値): </label> <textarea name="output2" id="output-2" rows="1" cols="50" readonly></textarea> </div> </form> <script> //name 属性が myForm の form 要素 const myForm = document.myForm; //myForm の name 属性が inputCity の要素(テキストフィールド) const inputCity = myForm.inputCity; //テキストフィールドの初期値(defaultValue プロパティ)を保存 const inputCityDefault = myForm.inputCity.defaultValue; //「Check」ボタンにクリックイベントのイベントリスナーを登録 myForm.check.addEventListener('click', ()=> { //入力された値を出力 myForm.output.textContent = inputCity.value; //初期値(defaultValue プロパティ)を出力 myForm.output2.textContent = inputCity.defaultValue; }); //「Change Default」ボタンにクリックイベントのイベントリスナーを登録 myForm.change.addEventListener('click', ()=> { //初期値(defaultValue プロパティ)を入力された値に変更 inputCity.defaultValue = inputCity.value; }) //「Reset Default」ボタンにクリックイベントのイベントリスナーを登録 myForm.resetDefault.addEventListener('click', ()=> { //初期値(defaultValue プロパティ)を保存した元の値にに戻す inputCity.defaultValue = inputCityDefault }) </script>
Check ボタンをクリックすると、現在入力されている値と初期値を表示します。
Change Default ボタンをクリックすると、defaultValue に現在入力されているを設定して変更ます。
Reset Default ボタンをクリックすると、defaultValue の値を元の値(保存した初期値)に戻します。
Reset ボタンをクリックすると、現在の defaultValue の値を表示します(デフォルトの動作)。
イベント
テキストフィールドがフォーム内に配置されている場合、フォームが送信される際の submiit イベントでその時点でテキストフィールドに入力されている値を確認するなどの処理ができます。
input 要素自体に発生するイベントについては イベントのタイミング を参照ください。
以下は送信ボタンをクリックするか、どちらかのテキストフィールドにカーソルを置いて return キーを押してフォームを送信する際に発生するフォームの submiit イベントで入力されている値を確認する例です。
input 要素には type="email" と required を指定して、入力した値がメールアドレスの形式でない場合や値が空の場合は HTML5 の検証を行うようにしています。
submiit イベントでは2つのメールアドレスが一致していない場合はメッセージを表示して、Event のメソッド preventDefault() でデフォルトの動作(この場合はフォームの送信)を中止しています。※ この記述をしないと、フォームは送信されてしまいます。
また、リセットボタンにはデフォルトの動作のコントロールのリセット以外に、表示されているエラーメッセージを非表示にするように click イベントを設定しています。
<form name="myForm" method="post"> <div> <label for="email1">E-mail: </label><br> <input type="email" required name="email1" id="email1" size="20"> </div> <div> <label for="email2">E-mail(確認): <span id="errorMsg" style="color: red;"></span> </label><br> <input type="email" required name="email2" id="email2" size="20"> </div> <div> <input type="submit" name="send" value="送信"> <input type="reset" name="reset" value="Reset"> </div> </form> <script> //name 属性が myForm の form 要素 const myForm = document.myForm; //メッセージを表示する id 属性が errorMsg の span 要素 const errorMsg = document.getElementById('errorMsg'); //フォームに submit イベントのイベントリスナーを登録 myForm.addEventListener('submit', (e) => { //メッセージを表示する span 要素のテキストを空に errorMsg.textContent = ''; //email1 と email2 の値が異なればメッセージを表示して送信を中止 if(myForm.email1.value !== myForm.email2.value ) { errorMsg.textContent = "メールアドレスが一致しません。"; //引数に渡されるイベント(e)のメソッドを使ってフォームの送信を中止 e.preventDefault(); } }); //Reset ボタンをクリックしたらメッセージもクリア myForm.reset.addEventListener('click', () => { //メッセージを表示する span 要素のテキストを空に errorMsg.textContent = ''; }); </script>
コピペの禁止
以下は1つ目のメールアドレスを入力するテキストフィールドではコピーを禁止し、2つ目のメールアドレスを入力するテキストフィールドではペースト(貼り付け)を禁止する例です。但し、このようにすると使いづらいフォームになります。
前述の例に copy と paste、input イベント(39行目〜70行目)を追加しています。HTML は同じです。
コピーの禁止では、copy イベントが発生したら、発生したイベント名を type プロパティで取得してメッセージに表示し、preventDefault() でデフォルトの動作(コピー)を中止しています(ペーストも同様)。
また、メッセージが表示されたままにならないように、入力操作が行われたら input イベントでメッセージをクリアしています。
<form name="myForm" method="post"> <div> <label for="email1">E-mail: </label><br> <input type="email" name="email1" id="email1" size="20" required> </div> <div> <label for="email2">E-mail(確認): <span id="errorMsg" style="color: red;"></span> </label><br> <input type="email" name="email2" id="email2" size="20" required> </div> <div> <input type="submit" name="send" value="送信"> <input type="reset" name="reset" value="リセット"> </div> </form> </div> <script> //name 属性が myForm の form 要素 const myForm = document.myForm; //メッセージを表示する id 属性が errorMsg の span 要素 const errorMsg = document.getElementById('errorMsg'); //name 属性が email1 の input 要素 const inputEmail1 = myForm.email1; //name 属性が email2 の input 要素 const inputEmail2 = myForm.email2; //フォームに submit イベントのイベントリスナーを登録 myForm.addEventListener('submit', (e) => { //メッセージを表示する span 要素のテキストを空に errorMsg.textContent = ''; //email1 と email2 の値が異なればメッセージを表示して送信を中止 if(myForm.email1.value !== myForm.email2.value ) { errorMsg.textContent = "メールアドレスが一致しません。"; //フォームの送信を中止 e.preventDefault(); } }); //Reset ボタンをクリックしたらメッセージもクリア myForm.reset.addEventListener('click', () => { //メッセージを表示する span 要素のテキストを空に errorMsg.textContent = ''; }); //email1 のテキストフィールドに copy イベントのイベントリスナーを登録 inputEmail1.addEventListener('copy', (e) => { // e.type で発生したイベント名を取得してメッセージを表示 errorMsg.textContent = e.type + ' はできません。'; //コピーを禁止(させない) e.preventDefault(); }); //email2 のテキストフィールドに paste イベントのイベントリスナーを登録 inputEmail2.addEventListener('paste', (e) => { errorMsg.textContent = e.type + ' はできません。'; //ペーストを禁止(させない) e.preventDefault(); }); //email1 のテキストフィールドに input イベントのイベントリスナーを登録 inputEmail1.addEventListener('input', () => { //入力された内容が変わるとメッセージをクリア errorMsg.textContent = ''; }); //email2 のテキストフィールドに input イベントのイベントリスナーを登録 inputEmail2.addEventListener('input', () => { //入力された内容が変わるとメッセージをクリア errorMsg.textContent = ''; }) </script>
フォームを使わない例
フォームを使わず、ボタンをクリックしたら入力されている値を使って何からの処理をする場合は、ボタンの click イベントを使うことができます。その他にも input 要素自体のイベントを使うこともできます。
以下は Reverse というボタンをクリックすると入力された文字列を逆順に出力する例です。
この例ではそれぞれの要素に document.getElementById() でアクセスしています。
入力された文字列を逆順で出力するには、入力された値(.value)を String オブジェクトのメソッド split() で1文字ずつ分解し、それを配列のメソッド reverse() で逆順に並べ替え、配列のメソッド join() で連結しています。
<input type="text" id="textInput" size="40"> <button type="button" id="reverse">Reverse</button> <button type="button" id="clear" class="clear">Clear</button> <div id="outputText" class="output"></div> <script> const textInput = document.getElementById('textInput'); const outputText = document.getElementById('outputText'); //Reverse ボタンに click イベントのイベントリスナーを登録 document.getElementById('reverse').addEventListener('click', () => { //入力された文字列を逆順にして出力 outputText.textContent = textInput.value.split('').reverse().join(''); }); //Clear ボタンに click イベントのイベントリスナーを登録 document.getElementById('clear').addEventListener('click', () => { //入力された値と出力をクリア outputText.textContent = ''; textInput.value = ''; }); </script>
input イベント
input イベントは、input 要素、select 要素、 textarea 要素の value が変更されたときに発生します。
change イベントが要素の変更が終わったとき(ユーザーが確定したとき)に発生するのに対して、input イベントは 要素の value の値が変化するたびに発生します。
各イベントの発生するタイミングの違いについては次項の「イベントのタイミング」を参照ください。
また、type="checkbox" または type="radio" の input 要素(チェックボックスやラジオボタン)では、代わりに change イベントを使用したほうが互換性が高いようです。
テキストフィールドの input イベント
以下はテキストフィールドのイベントの1つ、input イベントを使ってテキストフィールドの値が変化するたびに値を出力する例です。
この例では name 属性が textInput のテキストフィールドを querySelector() を使って取得しています。
addEventListener ではアロー関数を使っているので、引数(e)として渡されるイベントの target (イベントを発生させたオブジェクト)でテキストフィールドを参照してその値(e.target.value)を出力先に設定しています(アロー関数の代わりに function() を使えば、this で参照できます)。
<input type="text" name="textInput" size="40" placeholder="テキストを入力"> <p id="outputText" class="output"></p> <script> //テキストフィールド(name 属性が textInput)の input 要素を取得 const textInput = document.querySelector('input[name="textInput"]'); //出力先の id 属性が output の p 要素を取得 const outputText = document.getElementById('outputText'); //テキストフィールドに input イベントを登録 textInput.addEventListener('input', (e) => { //出力先の p 要素の textContent にテキストフィールドに入力された値を設定 outputText.textContent = e.target.value; }); </script>
input イベントの例
以下はテキストフィールドではなく、type="range" の input 要素(スライダー)に input イベントを設定して、スライダーの値を変更すると、リアルタイムで div 要素の大きさを変更する例です。
width: 50
height: 50
<p> width: <input type="range" name="width" min="5" max="300" value="50" step="1"> <span id="boxWidth">50</span> </p> <p> height: <input type="range" name="height" min="5" max="300" value="50" step="1"> <span id="boxHeight">50</span> </p> <div id="box"></div> <script> //id="box" の div 要素 const sampleBox = document.getElementById('box'); //id="boxWidth" の span 要素 const boxWidth = document.getElementById('boxWidth'); //id="boxHeight" の span 要素 const boxHeight = document.getElementById('boxHeight'); //name='width' の input 要素(スライダー)に input イベントのイベントリスナーを登録 document.querySelector('input[name="width"]').addEventListener('input', (e) => { //width のスライダーの値 const widthValue = e.currentTarget.value; //span 要素のテキストにスライダーの値を設定 boxWidth.textContent = widthValue; //スライダーの値を div 要素の width に設定 sampleBox.style.setProperty('width', widthValue + 'px'); }); //name='height' の input 要素(スライダー)に input イベントのイベントリスナーを登録 document.querySelector('input[name="height"]').addEventListener('input', (e) => { //height のスライダーの値 const heighthValue = e.currentTarget.value; //span 要素のテキストにスライダーの値を設定 boxHeight.textContent = heighthValue; //スライダーの値を div 要素の height に設定 sampleBox.style.setProperty('height', heighthValue + 'px'); }); </script>
関連項目
イベントの一覧:MDN イベントリファレンス
イベントのタイミング
同じ要素に発生するイベントでもタイプによりそれらの発生するタイミングが異なります。
input 要素、textarea 要素、select 要素では以下の入力イベントが使用できます。
イベント | 説明(発生するタイミング) |
---|---|
beforeinput | 要素の値が変更されようとしているときに発生 |
input | 要素の値が変更されるたびに発生 |
change | 要素の変更が終わったとき(ユーザーが確定したとき)に発生。テキストフィールドやテキストエリアの場合はフォーカスを失った時にイベントが発生 |
また、テキストフィールドやテキストエリアでは上記以外にも keyup や focus、blur などのイベントを設定することができます。
イベント | 説明(発生するタイミング) |
---|---|
blur | 要素がフォーカスを失ったときに発生 |
focus | 要素がフォーカスされたときに発生 |
keydown | 任意のキーが押されたときに発生 |
keypress | shift、fn、caps lock を除く任意のキーが押された状態にあるときに発生(非推奨→ keydown または beforeinput を使用) |
keyup | 任意のキーが (押された状態から) 解放されるときに発生 |
以下は異なるイベントを使ってテキストフィールドに入力された値を出力する例です。
テキストフィールドやテキストエリアの場合、change イベントは要素の変更が終わったとき(blur と同じタイミング)に発生しますが、input イベントや keyup イベントでは値が変更されるたびに発生します。
また、例えば beforeinput と keydown はほぼ同じタイミングで発生しますが、フォーカスが外れた際の挙動が異なっていたり、コピペでは発生しない等、イベントにより発生するタイミングが異なります。
そのため、処理する内容に応じて適切なイベントを選択します。
イベント | 出力(イベント発生時に取得する値) | 発生回数 |
---|---|---|
input | ||
beforeinput | ||
change | ||
keydown | ||
keyup | ||
focus | ||
blur |
上記はテキストフィールド(type="text" の input 要素)の例ですが、テキストエリア(textarea 要素)でも同じです。
以下は上記サンプルのコードです。
<input type="text" id="textInput" size="30" placeholder="テキストを入力"> <input type="button" id="clear" value="Reset"> <!-- 入力された値をそれぞれ発生したタイミングで出力欄(.output の td)に出力 --> <table> <tr> <th >イベント</th> <th>出力</th> <th>発生回数</th> </tr> <tr> <td>input</td> <td class="output"></td> <td class="eventCount"></td> </tr> <tr> <td>beforeinput</td> <td class="output"></td> <td class="eventCount"></td> </tr> ・・・中略・・・ <tr> <td>blur</td> <td class="output"></td> <td class="eventCount"></td> </tr> </table> <script> //id 属性が textInput の要素(テキストフィールド) const textInput = document.getElementById('textInput'); //クラスが output の td 要素の集まり(入力値の出力先) const outputs = document.getElementsByClassName('output'); //クラスが eventCount の td 要素の集まり(カウントの出力先) const eventCounts = document.getElementsByClassName('eventCount'); //イベントのリストの(配列) const events = ['input','beforeinput','change','keydown','keyup','focus','blur']; //それぞれのイベントの発生回数(0で初期化) const counts = Array(outputs.length); counts.fill(0); //イベントリスナーオブジェクト(addEventListener の第2引数に指定) const eventListeners = {}; //イベントごとにオブジェクトを作成 for(let i=0; i<events.length; i++) { eventListeners[events[i]] = { output : outputs[i], count : counts[i], countOut : eventCounts[i], handleEvent: function(e) { //output に指定された要素の textContent プロパティに入力された値を出力 this.output.textContent = e.target.value; //発生回数を1増加 this.count ++; //countOut に指定された要素の textContent プロパティに発生回数を出力 this.countOut.textContent = this.count; } }; } //addEventListener を使ってそれぞれのイベントを登録する関数の定義 function addMyEvents(eventTarget, event, output, count, countOut, eventListener) { //eventTarget に event で指定されたイベントを登録 eventTarget.addEventListener(event, eventListener, false ); } //上記関数を使って同じ要素に異なるイベントのイベントリスナーを登録 for(let i=0; i<events.length; i++) { addMyEvents(textInput, events[i], outputs[i], counts[i], eventCounts[i], eventListeners[events[i]]); } //id 属性が clear の要素に click イベントのイベントリスナーを登録 document.getElementById('clear').addEventListener('click', ()=> { //テキストフィールドの value プロパティに空文字を設定 textInput.value = ''; //td 要素の textContent プロパティに空文字を設定 for(let i=0; i<events.length; i++) { outputs[i].textContent = ''; eventCounts[i].textContent = ''; //オブジェクトのカウントをリセット eventListeners[events[i]].count = 0; } }); </script>
上記コードでは、addEventListener() の第2引数にリスナー関数の代わりにオブジェクトを指定して、handleEvent メソッドを実装し、プロパティで引数を渡しています。
以下のようにリスナー関数を使った場合、カウントのリセット(35行目)ができません(上記の方法以外に良い方法があるかもしれません)
const textInput = document.getElementById('textInput'); const outputs = document.getElementsByClassName('output'); const eventCounts = document.getElementsByClassName('eventCount'); const events = ['input','beforeinput','change','keydown','keyup','focus','blur']; let counts = Array(events.length); counts.fill(0); //addEventListener を使ってそれぞれのイベントを登録する関数の定義 function addMyEvents(eventTarget, event, output, count, countOut) { //eventTarget に event で指定されたイベントを登録 eventTarget.addEventListener(event, (e) => { //output に指定された要素の textContent プロパティに入力された値を出力 output.textContent = e.target.value; //発生回数を1増加 count ++; //countOut に指定された要素の textContent プロパティに発生回数を出力 countOut.textContent = count; }); } //上記関数を使って同じ要素に異なるイベントのイベントリスナーを登録 for(let i=0; i<events.length; i++) { addMyEvents(textInput, events[i], outputs[i], counts[i], eventCounts[i]); } //id 属性が clear の要素に click イベントのイベントリスナーを登録 document.getElementById('clear').addEventListener('click', ()=> { //テキストフィールドの value プロパティに空文字を設定 textInput.value = ''; //td 要素の textContent プロパティに空文字を設定 for(let i=0; i<events.length; i++) { outputs[i].textContent = ''; eventCounts[i].textContent = ''; //それぞれのカウントをクリアするつもり counts[i] = 0; //※ 実際にはクリアできない(それぞれの値は保持されたまま) } });
テキストエリア
テキストエリアは複数行の文章を入力できるテキスト入力欄で textarea 要素を使います。
テキストフィールドとは異なり、改行することができます。
<textarea name="comment" rows="3" cols="50" placeholder="コメントを入力"></textarea>
また、input 要素とは異なり、開始タグと終了タグのペアで使い、タグの間(<textarea>〜</textarea>)に記述された内容が初期値として使われます。
<textarea name="comment" rows="3" cols="50">この文字列が初期値として表示されます</textarea>
テキストエリアがフォーム内にある場合は、document.forms や elements を使って取得(アクセス)することができます。
以下は document.forms を使って name 属性が myForm の form 要素の name 属性が comment の elements プロパティ(textarea 要素)にアクセスしています。
<form name="myForm"> <div> <textarea name="comment" rows="3" cols="50"></textarea> </div> </form> <script> const myTextarea = document.myForm.comment; //以下でも同じこと ※ .forms は省略可能 //const myTextarea = document.forms.myForm.comment; //const myTextarea = document.forms['myForm'].comment; //const myTextarea = document.forms.myForm['comment']; //const myTextarea = document.forms.myForm.elements['comment']; console.log(myTextarea.cols); //50 </script>
フォーム内にない場合は(フォーム内にある場合でも)、 DOM のメソッドを使って取得(アクセス)することができます。
イベントはテキストフィールドとほぼ同じです。
値の取得 value
textarea 要素には HTML の value 属性はありませんが、<textarea>〜</textarea> に入力された値や記述された初期値はテキストフィールド同様、value プロパティで取得できます。
以下はボタンがクリックされたらテキストエリアの値を取得し、値が空か空白のみの場合はアラートを表示し、そうでなければ取得した値を div 要素の innerText プロパティに設定して出力する例です。
innerText の代わりに textContent を使うとテキストエリアに入力された改行は反映されません。
<textarea name="textArea" id="textArea" cols="30" rows="5"></textarea> <button type="button" id="btn">Click</button> <div id="output"></div> <script> document.getElementById('btn').addEventListener('click', () => { //テキストエリアに入力された値 const textAreaValue = document.getElementById('textArea').value; if(textAreaValue.trim() ==='') { alert('値が入力されていないか空白文字です。') }else{ document.getElementById('output').innerText = textAreaValue; //innerText の代わりに textContent を使うと改行は取り除かれます } }, false); </script>
textLength プロパティ
テキストエリアには、入力されている値の長さ(文字数)を表す読み取り専用のプロパティ textLength があります。textLength は value.length と同じです。
以下はテキストエリアに文字を入力すると、入力された文字数を表示し、100文字を超えると文字数を赤色で表示する例です。
0/100
以下の例では addEventListener のリスナー関数にアロー関数を使っているので、関数内でテキストエリアには e.currentTarget でアクセスしています。
テキストエリアの文字数は value.length または textLength で取得できます。空白文字や改行も文字数にカウントされます。
span 要素の文字色は setProperty() や style プロパティを使ってインラインスタイルで設定しています。
<textarea name="comment" rows="5" cols="50" placeholder="コメント"></textarea> <p><span id="count">0</span>/100</p> <script> //テキストエリア要素(name="comment" のテキストエリアがページに1つだけある場合) const textArea = document.querySelector('textarea[name="comment"]'); //文字数を出力する span 要素 const countOut = document.getElementById('count'); //上記 span 要素のスタイル const countOutStyle = countOut.style; //テキストエリアに input イベントを登録 textArea.addEventListener('input', (e) => { //テキストエリアに入力されている文字の長さ(文字数) const count = e.currentTarget.value.length; //または e.currentTarget.textLength; //span 要素に文字数を出力 countOut.textContent = count; //文字数が100より大きい場合は文字を赤色に if(count > 100) { countOutStyle.setProperty('color', 'red'); // または countOutStyle.color = 'red'; }else{ //100文字未満の場合は文字を元に戻す countOutStyle.removeProperty('color'); // または countOutStyle.color = null; } }); </script>
上記の例では、文字色の変更はインラインスタイルで設定していますが、別途クラスでスタイルを設定しておき、以下のようにクラスの操作で変更することもできます(HTML は同じなので省略)。
.warning { color: #fff; background-color: red; padding: 2px; }
const textArea = document.querySelector('textarea[name="comment"]'); const countOut = document.getElementById('count'); textArea.addEventListener('input', (e) => { const count = e.currentTarget.value.length; countOut.textContent = count; //文字数が100より大きい場合は文字のスタイルを変更 if(count > 100) { // warning クラスを追加 countOut.classList.add('warning'); }else{ // warning クラスを削除 countOut.classList.remove('warning'); } });
改行 \n
テキストフィールド(type="text" の input 要素)は1行の入力フィールドなので改行することができませんが、テキストエリア(textarea 要素)では入力時や値の設定時に改行することができます。
テキストエリアに改行を入れるには改行コード(\n:バックスラッシュと小文字の n)を使います。
また、テキストエリアに値を設定するには値の取得同様 value 属性を使います。
<textarea id="myTextarea"></textarea> <button type="button" id="setTextarea1">改行なし</button> <button type="button" id="setTextarea2">改行あり</button> <script> //テキストエリア const myTextareaElem = document.getElementById('myTextarea'); //改行なしの文字列 const noLineBreak = 'Hello World!' //改行(\n)を含む文字列 const withLineBreak = 'Hello \nWorld!' document.getElementById('setTextarea1').addEventListener('click', () => { //改行なしの文字列をテキストエリアに設定 myTextareaElem.value = noLineBreak; }); document.getElementById('setTextarea2').addEventListener('click', () => { //改行を含む文字列をテキストエリアに設定 myTextareaElem.value = withLineBreak; }); </script>
または、バッククォート(`)を使ったテンプレートリテラルで記述しても改行が反映されます。
//テンプレートリテラル const withLineBreak = `Hello World!`;
入力された値を出力
テキストエリアに入力された値を出力する際に、textContent と innerText プロパティでは改行の扱いが異なります。
textContent を使った出力ではテキストエリアの改行は反映されませんが、innerText を使った出力では改行が反映されます(<br> が挿入されます)。
<textarea id="myTextarea" cols="50" rows="5"></textarea> <button type="button" id="textContentOut">textContent</button> <button type="button" id="innerTextOut">innerText</button> <button type="button" id="clear">Clear</button> <div id="myOutput"></div> <script> //テキストエリア const myTextareaElem = document.getElementById('myTextarea'); //出力先の div 要素 const myOutputElem = document.getElementById('myOutput'); document.getElementById('innerTextOut').addEventListener('click', () => { //テキストエリアに入力された値を出力先に innerText を使って設定 myOutputElem.innerText = myTextareaElem.value; }); document.getElementById('textContentOut').addEventListener('click', () => { //テキストエリアに入力された値を出力先に textContent を使って設定 myOutputElem.textContent = myTextareaElem.value; }); document.getElementById('clear').addEventListener('click', () => { //テキストエリアの値をクリア myTextareaElem.value = ''; //出力先 div 要素の値をクリア myOutputElem.innerText = ''; }); </script>
改行を <br> に変換
テキストエリアに入力された値を innerHTML プロパティに設定して出力する場合などでは、改行コードは <br> に変換されないので、正規表現(String オブジェクトのメソッド)の replace() などを使って変換する必要があります。
以下は replace() を使って、文字列 str に含まれる全ての改行コード(\n)を <br> に変換する例です。
replace() の最初の引数は検索する文字列の正規表現で、この場合の検索対象は改行コードの \n で、一致するもの全てを検索するように g フラグを指定します(正規表現では文字列を / で囲みます)。
2番目の引数は置き換える文字列、この場合は改行タグの <br> になります。
let value = str.replace(/\n/g, '<br>');
以下のように関数にしておくこともできます。PHP には改行コードを <br> に変換する nl2br() という組み込み関数が用意されています。
//改行コードを <br> に変換する関数を定義 const nl2br = (str) => { return str.replace(/\n/g, '<br>'); } //改行コードを含む文字列 let taString = 'Hello \nWorld!'; //nl2br() で改行コードを <br> に変換してコンソールに出力 console.log(nl2br(taString)); //Hello <br>World!
以下はボタンをクリックすると、テキストエリアに入力された値の改行コードを <br> に変換して、div 要素の innerHTML プロパティに設定して出力する例です。
入力された値を innerHTML プロパティを使って出力する際はエスケープして出力する必要があるので、以下では h() という関数で入力された値をエスケープしています。
<textarea id="myTextarea" cols="50" rows="5"></textarea> <button type="button" id="convert">出力</button> <button type="button" id="clear">クリア</button> <div id="myOutput"></div> <script> //特殊文字をエスケープして無害化する関数 function h(str){ return str.replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/</g, '<') .replace(/>/g, '>'); } //テキストエリア const myTextareaElem = document.getElementById('myTextarea'); //出力先の div 要素 const myOutputElem = document.getElementById('myOutput'); document.getElementById('convert').addEventListener('click', () => { //テキストエリアの値をエスケープ処理 const escapedValue = h(myTextareaElem.value); //改行コードを <br> タグに変換 const convertedValue = escapedValue.replace(/\n/g, '<br>'); //出力先 div 要素の innerHTML プロパティに変換した値を設定 myOutputElem.innerHTML = convertedValue; }); document.getElementById('clear').addEventListener('click', () => { //テキストエリアの値をクリア myTextareaElem.value = ''; /出力先 div 要素の値をクリア myOutputElem.innerHTML = ''; }); </script>
チェックボックス
input 要素の type 属性に checkbox を指定するとチェックボックスを生成します。関連するチェックボックス項目をグループとしてまとめる(認識させる)には name 属性に同じ値を指定します。
チェックボックスは複数選択が可能です。また、checked 属性を指定するとその項目はあらかじめチェックの付いた状態になります。
<input type="checkbox" name="music" value="jazz" checked> Jazz <input type="checkbox" name="music" value="hiphop"> Hip Hop <input type="checkbox" name="music" value="classic"> Classic
:checked 擬似クラス
:checked はチェックボックスやラジオボタン、オプション項目 (option 要素) がチェックされた場合に適用される CSS の擬似クラスです。
以下は :checked 擬似クラスを使って選択されたチェックボックスに続く span 要素の文字色を変更する例です。また label 要素を使ってそれぞれのチェックボックスと関連付けしているので、ラベルの文字をクリックしてもチェックボックスが選択・解除されます。
<div class="checkbox_sample"> <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked> <label for="cboxJazz"> Jazz </label> <input type="checkbox" name="music" id="cboxHiphop" value="hiphop"> <label for="cboxHiphop"> Hip Hop </label> <input type="checkbox" name="music" id="cboxClassic" value="classic"> <label for="cboxClassic"> Classic </label> </div>
.checkbox_sample input:checked + label { color: red; }
チェックボックスの取得
チェックボックスがフォーム内にある場合は、document.forms や elements を使って取得(アクセス)することができます。
同じ名前(値)の name 属性が複数ある場合、それらは配列のようなオブジェクト(NodeList)で、各要素にはインデックス(添字)を使ってアクセスします。
<form name="myForm"> <input type="checkbox" name="music" value="jazz" checked> Jazz <input type="checkbox" name="music" value="hiphop"> Hip Hop <input type="checkbox" name="music" value="classic"> Classic </form> <script> //name 属性が myForm の form 要素内にある name 属性が music の全ての要素 const musicCheckboxes = document.myForm.music; //以下でも同じこと ※ .forms は省略可能 //const musicCheckboxes = document.forms.myForm.music; //const musicCheckboxes = document.forms['myForm'].music; //const musicCheckboxes = document.forms.myForm['music']; //const musicCheckboxes = document.forms.myForm.elements['music']; //配列のようなオブジェクトなので length プロパティがある console.log(musicCheckboxes.length); //3 //2番目の要素の値(value プロパティ)をコンソールに出力(インデックスを使ってアクセス) console.log(musicCheckboxes[1].value); //hiphop </script>
項目が1つだけの場合
チェックボックスの項目が1つだけ(同じ名前の name 属性が1つだけ)の場合、以下の方法でアクセスすると、その要素1つが取得され配列(のようなオブジェクト)ではありません。
<form name="myForm"> <input type="checkbox" name="agree" value="agreed"> 同意する </form> <script> const agreeCheckbox = document.myForm.agree; //取得した要素の値(value プロパティ)を出力 console.log(agreeCheckbox.value); //agreed console.log(agreeCheckbox[0].value); // 配列ではないので以下のエラー //Uncaught TypeError: Cannot read property 'value' of undefined </script>
チェックボックスがフォーム内にない場合は(フォーム内にある場合でも)、querySelectorAll() や getElementsByName() などの DOM のメソッドを使って取得することができます。
以下の例では document.querySelectorAll() の引数に 'input[name="music"]' を渡していますが、環境に応じてセレクタを指定します。
<input type="checkbox" name="music" value="jazz" checked> Jazz <input type="checkbox" name="music" value="hiphop"> Hip Hop <input type="checkbox" name="music" value="classic"> Classic <script> //全ての name="music" の input 要素(NodeList) const musicCheckboxes = document.querySelectorAll('input[name="music"]'); //getElementsByName で取得する場合 //const musicCheckboxes = document.getElementsByName('music'); console.log(musicCheckboxes.length); //3 console.log(musicCheckboxes[2].value); //classic </script>
name 属性の値に [] を付けて配列としてデータを送信する
PHP でチェックボックスの値を配列で受け取る場合、以下のように name 属性の値に [] を付けて、配列としてデータを送信します。
<form name="myForm"> <input type="checkbox" name="music[]" value="jazz" checked> Jazz <input type="checkbox" name="music[]" value="hiphop"> Hip Hop <input type="checkbox" name="music[]" value="classic"> Classic <button name="send">送信</button> </form>
上記の場合、以下のいずれかで name="music[]" の要素の集まり(NodeList)にアクセスすることができます。
const musicCheckboxes1 = document.myForm['music[]']; const musicCheckboxes2 = document.forms.myForm.elements['music[]']; const musicCheckboxes3 = document.querySelectorAll('[name="music[]"]'); //当然ですが、以下ではアクセスできません(NG) const musicCheckboxes1 = document.myForm.music[]; //エラー //Uncaught SyntaxError: Unexpected token ']'
または、class を設定して getElementsByClassName() でアクセスするなど他にも方法はあります。
関連ページ: PHP 複数のチェックボックス
値の取得 value
チェックボックスの各要素の value 属性に設定されている値は value プロパティで取得できます。
以下は for 文を使ってチェックボックスの各要素の value 属性に設定されている値をコンソールに出力する例です。
<input type="checkbox" name="music" value="jazz" checked> Jazz <input type="checkbox" name="music" value="hiphop"> Hip Hop <input type="checkbox" name="music" value="classic"> Classic <script> //querySelector() で name="music" の最初の要素を取得してその value プロパティを出力 console.log(document.querySelector('input[name="music"]').value); //jazz // querySelectorAll() で name="music" の全ての要素を取得 const musicCheckboxes = document.querySelectorAll('input[name="music"]'); for(let i=0; i<musicCheckboxes.length; i++) { //各要素の値をコンソールに出力 console.log( 'musicCheckboxes[' + i + '] : ' + musicCheckboxes[i].value); } //以下は出力結果 //musicCheckboxes[0] : jazz //musicCheckboxes[1] : hiphop //musicCheckboxes[2] : classic </script>
musicCheckboxes は配列のようなオブジェクト(NodeList)なので NodeList のメソッド forEach() や ES6 の for of 文が使えます(いずれも IE 未対応)。
const musicCheckboxes = document.querySelectorAll('input[name="music"]'); //NodeList のメソッド forEach() musicCheckboxes.forEach((elem,index) => { console.log('musicCheckboxes[' + index + '] : ' + elem.value); }); //以下は出力結果 //musicCheckboxes[0] : jazz //musicCheckboxes[1] : hiphop //musicCheckboxes[2] : classic //ES6 の for of 文 for (let elem of musicCheckboxes) { console.log(elem.value); } //以下は出力結果 //jazz //hiphop //classic
プロパティ
チェックボックスまたはラジオボタン(type 属性が checkbox または radio)には以下のようなプロパティがあります。
プロパティ | 説明 |
---|---|
checked | 要素の現在の選択状態を参照または設定(真偽値)。選択されている場合は true、選択されていない場合は false |
defaultChecked | HTML で指定されていた選択状態を参照または設定(真偽値)。HTML で checked 属性が指定されている場合は true、指定されていない場合は false |
indeterminate | チェックボックスやラジオボタンの選択状態が不確定であるかどうかを返します。チェックボックスをクリックするとその値は false になります。 |
以下はチェックボックスの各要素のプロパティを確認及び変更する例です。
初期状態では、最初のチェックボックスの項目は checked 属性が指定されているので、checked と defaultChecked の値が true になっています。
checked や defaultChecked の値は変更(設定)可能です。また、checked の値はユーザーの操作により変化します。
<input type="checkbox" name="music" value="jazz" checked> Jazz <input type="checkbox" name="music" value="hiphop"> Hip Hop <input type="checkbox" name="music" value="classic"> Classic <script> const musicCheckboxes = document.querySelectorAll('[name="music"]'); //初期状態の各要素のプロパティを確認 for(let i=0; i<musicCheckboxes.length; i++) { console.log( i + ' checked : ' + musicCheckboxes[i].checked + ' /defaultChecked : '+ musicCheckboxes[i].defaultChecked ); } //出力結果 /* 0 checked : true /defaultChecked : true 1 checked : false /defaultChecked : false 2 checked : false /defaultChecked : false */ musicCheckboxes[0].defaultChecked = false; musicCheckboxes[0].checked = false; musicCheckboxes[1].defaultChecked = true; musicCheckboxes[1].checked = true; // 上記設定後のプロパティの確認 for(let i=0; i<musicCheckboxes.length; i++) { console.log( i + ' checked : ' + musicCheckboxes[i].checked + ' /defaultChecked : '+ musicCheckboxes[i].defaultChecked ); } //出力結果 /* 0 checked : false /defaultChecked : false 1 checked : true /defaultChecked : true 2 checked : false /defaultChecked : false */ </script>
選択状態を取得
チェックボックスの選択状態を取得及び変更するには checked プロパティを使います。選択されている要素を取得するだけなら次項の :checked 擬似クラスを利用する方が簡単です。
チェックボックスの各要素の checked プロパティには、その要素が選択されている場合は true、選択されていない場合は false が格納されています。
以下の例では querySelectorAll() で name 属性が check のチェックボックスを全て取得して変数 checkboxes に格納しています。変数に格納されているのは配列のようなオブジェクトです。
ボタンがクリックされたら for 文でチェックボックスの各要素の checked プロパティを調べ、値が true の場合(そのチェックボックスが選択されている場合)はそのチェックボックスの値(value)とインデックスをコンソールに出力します。
<div> <input type="checkbox" name="check" value="1"> value 1 <input type="checkbox" name="check" value="2"> value 2 <input type="checkbox" name="check" value="3"> value 3 </div> <button type="button" name="checkButton">Check</button> <script> //name="check" の全てのチェックボックスの要素を取得(NodeList) const checkboxes = document.querySelectorAll('[name="check"]'); //name="checkButton" のボタン要素を取得 const btn = document.querySelector('[name="checkButton"]'); //ボタンに click イベントのイベントリスナーを登録 btn.addEventListener('click', () => { //for 文で各要素の checked プロパティを調べる for(let i=0; i<checkboxes.length; i++) { //checked プロパティが true の場合 if(checkboxes[i].checked === true) { // if(checkboxes[i].checked) でも同じ //checkboxes[i] は選択されているチェックボックスなのでその値とインデックスを出力 console.log('index: ' + i + ' value: ' + checkboxes[i].value); } } }); </script>
querySelectorAll() で取得した checkboxes は配列のようなオブジェクト(NodeList)なので NodeList のメソッド forEach() や ES6 の for of 文が使えます(いずれも IE 未対応)。
以下は16〜22行目の for 文を NodeList のメソッド forEach() で書き換えた例です。
btn.addEventListener('click', () => { //NodeList のメソッド forEach() checkboxes.forEach((elem, index) => { //checked プロパティが true の場合 if (elem.checked) { console.log('index: ' + index + ' value: ' + elem.value); } }); });
以下は前述の例とほぼ同じですが、name 属性が music のチェックボックスを全て取得しておき、ボタンがクリックされたら各要素の checked プロパティを調べ、値が true の場合はそのチェックボックスの値を取得して配列 checked_list に追加し、出力先の div 要素の textContent プロパティに配列 checked_list の各要素を半角スペースで繋げた値を設定して出力しています。
<div> <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked> <label for="cboxJazz"> Jazz </label> <input type="checkbox" name="music" id="cboxHiphop" value="hiphop"> <label for="cboxHiphop"> Hip Hop </label> <input type="checkbox" name="music" id="cboxClassic" value="classic"> <label for="cboxClassic"> Classic </label> </div> <button type="button" name="checkButton">Check</button> <div id="output"></div> <script> //name="music" の全てのチェックボックスの要素を取得(NodeList) const musicCheckboxes = document.querySelectorAll('[name="music"]'); //出力先の div 要素 const output = document.getElementById('output'); //ボタンに click イベントのイベントリスナーを登録 document.querySelector('[name="checkButton"]').addEventListener('click', () => { //選択されたチェックボックスの値を格納する配列 const checked_list = []; //for 文で各要素の checked プロパティを調べる for(let i=0; i<musicCheckboxes.length; i++) { //checked プロパティが true の場合 if (musicCheckboxes[i].checked) { //配列 hecked_list に値を追加 checked_list.push(musicCheckboxes[i].value); } } //選択されたチェックボックスの値をスペース区切りで繋げて出力 output.textContent = checked_list.join(' '); }); </script>
以下は前述の例に「Select All」及び「Clear All」というボタンを追加して、「Select All」をクリックすると全てのチェックボックスを選択された状態にし、「Clear All」をクリックすると全てのチェックボックスの選択を解除します。
<div> <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked> <label for="cboxJazz"> Jazz </label> <input type="checkbox" name="music" id="cboxHiphop" value="hiphop"> <label for="cboxHiphop"> Hip Hop </label> <input type="checkbox" name="music" id="cboxClassic" value="classic"> <label for="cboxClassic"> Classic </label> </div> <button type="button" name="checkButton">Check</button> <button type="button" name="selectAll">Select All</button> <button type="button" name="clearAll">Clear All</button> <div id="output"></div> <script> //name="music" の全てのチェックボックス要素を取得 const musicCheckboxes = document.querySelectorAll('[name="music"]'); const output = document.getElementById('output'); //Check ボタンに click イベントのイベントリスナーを登録(前述の例と同じ) document.querySelector('[name="checkButton"]').addEventListener('click', () => { const checked_list = []; for(let i=0; i<musicCheckboxes.length; i++) { if (musicCheckboxes[i].checked) { //(musicCheckboxes[i].checked === true) checked_list.push(musicCheckboxes[i].value); } } output.textContent = checked_list.join(' '); }); //Select All ボタンに click イベントのイベントリスナーを登録(全てを選択状態に) document.querySelector('[name="selectAll"]').addEventListener('click', () => { //ループで各要素の checked プロパティに true を設定 for(let i=0; i<musicCheckboxes.length; i++) { musicCheckboxes[i].checked = true; } }); //Clear All ボタンに click イベントのイベントリスナーを登録(全ての選択を解除) document.querySelector('[name="clearAll"]').addEventListener('click', () => { //ループで各要素の checked プロパティに false を設定 for(let i=0; i<musicCheckboxes.length; i++) { musicCheckboxes[i].checked = false; } }); </script>
選択されたチェックボックスを取得
選択されたチェックボックスを取得するには、前述のように対象の全てのチェックボックスの checked プロパティを調べる方法の他に、:checked 擬似クラスを使ったセレクタを querySelectorAll() に指定する方法があります。
以下はボタンをクリックしたら、その時点で選択された状態にあるチェックボックスの要素を querySelectorAll() を使って取得する例です。
querySelectorAll() の引数には :checked 擬似クラスを使った CSS セレクターを指定します。name 属性の値が check で選択されている状態の要素のセレクタは '[name="check"]:checked' と記述できます。
<div> <input type="checkbox" name="check" value="1"> value 1 <input type="checkbox" name="check" value="2"> value 2 <input type="checkbox" name="check" value="3"> value 3 </div> <button type="button" name="checkButton">Check</button> <script> //name="checkButton" のボタン要素を取得 const btn = document.querySelector('[name="checkButton"]'); //ボタンに click イベントのイベントリスナーを登録 btn.addEventListener('click', () => { //選択されている(:checked)状態の name="check" の要素全てを取得(NodeList) const checkedItems = document.querySelectorAll('[name="check"]:checked'); //選択されている状態の要素全ての値(value)を出力(全ての要素の checked プロパティは true) for(let i=0; i<checkedItems.length; i++) { console.log('value: ' + checkedItems[i].value); } }); </script>
以下もボタンがクリックされたら、選択された状態のチェックボックスを取得する例です。
<div> <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked> <label for="cboxJazz"> Jazz </label> <input type="checkbox" name="music" id="cboxHiphop" value="hiphop"> <label for="cboxHiphop"> Hip Hop </label> <input type="checkbox" name="music" id="cboxClassic" value="classic"> <label for="cboxClassic"> Classic </label> </div> <button type="button" name="checkButton">Check</button> <div id="output"></div> <script> //出力先の div 要素 const output = document.getElementById('output'); //name="music" の全てのチェックボックス要素(NodeList) const musicCheckboxes = document.querySelectorAll('[name="music"]'); //Check ボタンに click イベントのイベントリスナーを登録 document.querySelector('[name="checkButton"]').addEventListener('click', () => { //name="music" の選択された(:checked の)チェックボックス要素 const checkedBoxes = document.querySelectorAll('[name="music"]:checked'); //選択されたチェックボックスの値を格納する配列 const checked_list = []; //ループで各要素の値(value)を配列に追加 for(let i=0; i<checkedBoxes.length; i++) { checked_list.push(checkedBoxes[i].value); } //選択されたチェックボックスの値を出力 output.textContent = checked_list.join(' '); }); </script>
また、この例では以下の CSS を設定して、選択されたチェックボックスの項目の文字色を赤にしています。
input:checked + label { color: red; }
イベント
チェックボックスでは項目が選択・解除される際に input 及び change イベントが発生します。
input イベントは要素の値が変更されるたびに発生し、change イベントは要素の変更が終わったときに発生しますが、チェックボックスの場合は項目が選択・解除される際にほぼ同時に発生します(input イベントの方が先に発生します)。
HTML5 仕様書では、input イベントはユーザーがコントロールの状態を変更するたびに発生することになっていますが、チェックボックスやラジオボタンでは change イベントを使用するようにしたほうが互換性が高いようです(HTMLElement: input イベント)。
以下は change イベントを使って、選択及び解除された際にチェックボックスの value の値を出力する例です。この例の場合、同じ値の name 属性が複数あるので、その全ての要素を querySelectorAll() で取得しています。
そして for 文でそれぞれの要素に addEventListener() を使って change イベントのイベントリスナーを登録しています。
addEventListener() ではアロー関数を使っているので、イベントを登録した要素は e.currentTarget、発生した要素は e.target で参照できます(function 文を使えば this で、イベントを登録した要素を参照できます)。
発生した要素の checked プロパティを調べて true であれば、その要素が選択されたことになります。
<input type="checkbox" name="check" value="1"> value 1 <input type="checkbox" name="check" value="2"> value 2 <input type="checkbox" name="check" value="3"> value 3 <script> //name 属性が check の要素を querySelectorAll() で全て取得 const checkboxes = document.querySelectorAll('[name="check"]'); //for 文で各要素にイベント処理を設定 for(let i=0; i<checkboxes.length; i++) { // 各要素に change イベントのリスナーを登録 checkboxes[i].addEventListener('change', (e) => { //その要素(e.currentTarget)の checked プロパティを調べる if( e.currentTarget.checked ) { //true であれば選択された console.log(e.currentTarget.value + 'が選択されました。'); }else{ //false であれば(true でなければ)選択されていない console.log(e.currentTarget.value + 'が解除されました。'); } }) } </script>
IE をサポートする必要がなければ、上記の for 文の代わりに NodeList のメソッド forEach() や ES6 の for of 文が使えます。
//ES6 の for of 文を使う場合 for(elem of checkboxes) { elem.addEventListener('change', (e) => { if( e.currentTarget.checked ) { console.log(e.currentTarget.value + 'が選択されました。'); }else{ console.log(e.currentTarget.value + 'が解除されました。'); } }) } //NodeList の forEach() メソッドを使う場合 checkboxes.forEach((elem) => { elem.addEventListener('change', (e) => { if( e.currentTarget.checked ) { console.log(e.currentTarget.value + 'が選択されました。'); }else{ console.log(e.currentTarget.value + 'が解除されました。'); } }) });
以下はチェックボックスの選択状態が変更された際に発生する change 及び input イベントのタイミングを確認する例です。
ほぼ同じタイミングで発生した要素の値がそれぞれの出力先(id が changeEvent と inputEvent の span 要素)に表示されます。コンソールへの出力を確認すると input イベントの方が先に出力されています。
また、change イベントではその時点で選択されているチェックボックスの値(value)を「Checked Items」に出力しています。
<div> <label><input type="checkbox" name="check" value="1"> value 1 </label> <label><input type="checkbox" name="check" value="2"> value 2 </label> <label><input type="checkbox" name="check" value="3"> value 3 </label> </div> <p>change event: <span id="changeEvent"></span></p> <p>input event: <span id="inputEvent"></span></p> <p>Checked Items: <span id="checkedItems"></span></p> <script> //name 属性が check の要素を querySelectorAll() で全て取得 const checkboxes = document.querySelectorAll('[name="check"]'); //change イベントが発生した際にメッセージを出力する span 要素 const changeEventOut = document.getElementById('changeEvent'); //input イベントが発生した際にメッセージを出力する span 要素 const inputEventOut = document.getElementById('inputEvent'); //change イベントが発生した際に選択されているチェックボックスの値を出力する span 要素 const checkedItems = document.getElementById('checkedItems'); //選択された全てのチェックボックスの値を格納する配列 let checked_list = []; //for 文で各要素に change イベントのイベントリスナーを登録 for(let i=0; i<checkboxes.length; i++) { checkboxes[i].addEventListener('change', (e) => { //イベントが発生したらコンソールに「change event」と出力 console.log('change event'); //イベントの発生した要素(e.target)の checked プロパティを調べる if( e.target.checked ) { //その要素が選択された場合(checked が true の場合) changeEventOut.textContent = e.target.value + 'が選択されました。'; }else{ //その要素の選択が解除された場合(checked が false の場合) changeEventOut.textContent = e.target.value + 'が解除されました。'; } //選択されたチェックボックスの値を格納する配列を初期化 checked_list = []; //全てのチェックボックスの checked を調べて true であれば配列に追加 for(let j=0; j<checkboxes.length; j++) { if (checkboxes[j].checked) { checked_list.push(checkboxes[j].value); } } //選択された全てのチェックボックスの値を出力 checkedItems.textContent = checked_list.join(' '); }); } //for 文で各要素に input イベントのイベントリスナーを登録 for(let i=0; i<checkboxes.length; i++) { checkboxes[i].addEventListener('input', (e) => { //イベントが発生したらコンソールに「input event」と出力 console.log('input event'); //イベントの発生した要素(e.target)の checked プロパティを調べる if( e.target.checked ) { //その要素が選択された場合(checked が true の場合) inputEventOut.textContent = e.target.value + 'が選択されました。'; }else{ //その要素の選択が解除された場合(checked が false の場合) inputEventOut.textContent = e.target.value + 'が解除されました。'; } }); } </script>
以下はそれぞれが独立した(name 属性の値が異なる)チェックボックスにイベントを設定する例で、チェックボックスを選択・解除することでその内容に合わせてリアルタイムで表示を変更します。
それぞれのチェックボックスに関連性はないので、個別にイベントリスナーを登録します。
チェックボックスのイベントは change を使っていますが、input イベントでもほぼ同じです。但し、スライダー(type="range" の input 要素)の変更をリアルタイムで反映されるには、input イベントを設定します(イベントのタイミング)。
<p id="target">Lorem ipsum dolor sit amet, ... blanditiis.</p> <input type="checkbox" id="border" value="3px solid #ccc"> Border <input type="checkbox" id="bgColor" value="#CEDDF7"> Background Color <input type="checkbox" id="fontWeight" value="700"> Bold <p> Padding: <input type="range" id="padding" min="0" max="30" value="0" step="1"> <span id="paddingVal">0</span> </p> <script> //操作対象の id が target の p 要素 const target = document.getElementById('target'); //スライダーの値を出力する id が paddingVal の span 要素 const paddingVal = document.getElementById('paddingVal'); //id が border のチェックボックスにイベントリスナーを登録 document.getElementById('border').addEventListener('change', (e) => { if( e.currentTarget.checked ) { //チェックボックスが選択された場合(対象要素のスタイルを設定) target.style.setProperty('border', e.currentTarget.value); }else{ //チェックボックスが解除された場合(対象要素のスタイルを削除) target.style.removeProperty('border'); } }); //id が bgColor のチェックボックスにイベントリスナーを登録 document.getElementById('bgColor').addEventListener('change', (e) => { if( e.currentTarget.checked ) { target.style.setProperty('background-color', e.currentTarget.value); }else{ target.style.removeProperty('background-color'); } }); //id が fontWeight のチェックボックスにイベントリスナーを登録 document.getElementById('fontWeight').addEventListener('change', (e) => { if( e.currentTarget.checked ) { target.style.setProperty('font-weight', e.currentTarget.value); }else{ target.style.removeProperty('font-weight'); } }); //id が padding の input 要素(スライダー)にイベントリスナーを登録 document.getElementById('padding').addEventListener('input', (e) => { //スライダーの値 const paddingValue = e.currentTarget.value; //span 要素のテキストにスライダーの値を設定 paddingVal.textContent = paddingValue; //スライダーの値を対象要素の padding に設定 target.style.setProperty('padding', paddingValue + 'px'); }); </script>
上記の場合、イベントリスナーをチェックボックスに登録する操作は同じなので、以下のように関数にした方が記述が短くなります。
//イベントリスナーを登録する関数 const addMyChangeListener = (id, prop )=> { document.getElementById(id).addEventListener('change', (e) => { if( e.currentTarget.checked ) { //チェックボックスが選択された場合(対象要素のスタイルを設定) target.style.setProperty(prop, e.currentTarget.value); }else{ //チェックボックスが解除された場合(対象要素のスタイルを削除) target.style.removeProperty(prop); } }); } //上記関数を使ってリスナーを登録 addMyChangeListener('border', 'border'); addMyChangeListener('bgColor', 'background-color'); addMyChangeListener('fontWeight', 'font-weight');
イベントの移譲
親要素で子要素のイベントを検知
change イベントは input、select、textarea 要素においてユーザーによる要素の値の変更が確定したときに発生するイベントで、div 要素では発生しません。
但し、例えば div 要素の子要素にチェックボックスの input 要素がある場合、チェックボックスで発生したイベントは上位要素に順番に伝播(バブリング)します。
これを利用すると、div 要素にイベントリスナーを登録しておいてその子要素のイベントを捉えることができます(イベントの移譲/Event delegation)。
以下はチェックボックスを囲む div 要素に chnge イベントのイベントリスナーを登録し、チェックボックスを変更した際に発生する change イベントを検知する例です。
リスナー関数内では e.target がイベントが発生した要素になるので、その type 属性が checkbox であればチェックボックスで発生したイベントと判定しています。
そしてイベントの発生した要素の checked プロパティの値が true であればチェックボックスが選択されたことになるので、その値(e.target.value)をアラート表示しています。
checked プロパティの値が true でない(false の)場合は、チェックボックスの選択が解除されたことになります。
<div id="checkboxWrapper"> <input type="checkbox" name="check" value="1">value 1 <input type="checkbox" name="check" value="2">value 2 <input type="checkbox" name="check" value="3">value 3 </div> <script> // チェックボックスを囲む div 要素 const wrapperDiv = document.getElementById('checkboxWrapper'); // div 要素に change イベントのリスナーを登録 wrapperDiv.addEventListener('change', (e) => { //イベントが発生した要素(e.target)の type 属性が checkbox であれば if( e.target.type === 'checkbox' ) { //checked プロパティが true であればチェックボックスが選択された if(e.target.checked === true) { alert('value ' + e.target.value + 'が選択されました'); }else{ alert('value ' + e.target.value + 'が解除されました'); } } }); </script>
全てのチェックボックスにイベントリスナーを登録しなくて済むので記述が簡単になります。また、動的にチェックボックスを追加してもそれらに対してイベントは適用されます。
以下もチェックボックスの親要素の div 要素に chnge イベントのイベントリスナーを登録し、チェックボックスを変更した際に発生する change イベントを検知する例です。
リスナー関数内では e.target がイベントが発生した要素になりますが、e.currentTarget はイベントを登録している要素(div 要素)になります。以下では確認のためにe.target と e.currentTarget に該当する要素の id の値を出力しています(38〜40行目)。
また、イベントが発生した時点で選択されているチェックボックスの要素は querySelectorAll() の引数に :checked 擬似クラスを使ったセレクタを指定して取得しています(43行目)。
<div id="checkboxWrapper"> <input type="checkbox" name="check" value="1" id="checkbox1"> <label for="checkbox1">value 1 </label> <input type="checkbox" name="check" value="2" id="checkbox2"> <label for="checkbox2">value 2 </label> <input type="checkbox" name="check" value="3" id="checkbox3"> <label for="checkbox3">value 3 </label> </div> <p>change event: <span id="changeEvent"></span></p> <p>e.target: <span id="eTarget"></span></p> <p>e.currentTarget: <span id="eCurrentTarget"></span></p> <p>Checked Items: <span id="checkedItemsOut"></span></p> <script> // チェックボックスを囲む div 要素 const wrapperDiv = document.getElementById('checkboxWrapper'); // メッセージを出力する span 要素 const changeEventOut = document.getElementById('changeEvent'); // e.target の値を出力する span 要素 const eTarget = document.getElementById('eTarget'); // e.currentTarget の値を出力する span 要素 const eCurrentTarget = document.getElementById('eCurrentTarget'); // 選択されている要素の値を出力する span 要素 const checkedItemsOut = document.getElementById('checkedItemsOut'); wrapperDiv.addEventListener('change', (e) => { //イベントが発生した要素の type 属性が checkbox であれば if( e.target.type === 'checkbox' ) { //要素の checked プロパティを調べる if( e.target.checked ) { //checked プロパティが true の場合 changeEventOut.textContent = e.target.value + 'が選択されました。'; }else{ //checked プロパティが true でない場合 changeEventOut.textContent = e.target.value + 'が解除されました。'; } //イベントの target プロパティで取得する要素の id 属性の値を出力 eTarget.textContent = e.target.id; //イベントの currentTarget プロパティで取得する要素の id 属性の値を出力 eCurrentTarget.textContent = e.currentTarget.id; } //選択されている(:checked)状態の name="check" の要素全て(NodeList)を取得 const checkedItems = document.querySelectorAll('[name="check"]:checked'); //選択されている全てのチェックボックスの値を格納する配列 const checked_list = []; //NodeList の forEach() メソッドを使ってチェックボックスの値を配列に追加 checkedItems.forEach((elem) => { checked_list.push(elem.value); }); //選択された全てのチェックボックスの値を出力 checkedItemsOut.textContent = checked_list.join(' '); }); </script>
イベントを親要素に設定すれば、動的に子要素を追加・削除しても問題ありません(動的に追加/削除)
セレクトボックス
セレクトボックスはセレクトボックス全体を定義する select 要素とその子要素として各項目を定義する option 要素で構成され、必要に応じて optgroup 要素で option 要素をグループ化することができます。
select 要素はフォームコントロールとみなされるので elements プロパティに含まれますが、option 要素や optgroup 要素は elements プロパティには含まれません。
セレクトボックスには単一選択型のプルダウンリストと複数項目を表示するリストボックスがあります。
select 要素に multiple 属性や size 属性を指定しない場合は単一選択型のプルダウンリストになります。
以下は単一選択型のプルダウンリストのセレクトボックスの例です。size 属性は省略していますが、size 属性に1を指定しても単一選択型のプルダウンリストになります。
項目を初期状態で選択状態にする selected 属性を option 要素のいずれにも指定していない場合は、最初の option 要素が選択状態になります。
<select name="borough"> <option value="manhattan">Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens">Queens</option> <option value="bronx">Bronx</option> <option value="staten">Staten Island</option> </select>
option 要素に selected 属性を指定すると、その項目を初期状態で選択状態にします。以下は2番目の option 要素に selected 属性を指定しているので、その項目が表示(選択)されています。
<select name="borough"> <option value="manhattan">Manhattan</option> <option value="brooklyn" selected>Brooklyn</option> <option value="queens">Queens</option> <option value="bronx">Bronx</option> <option value="staten">Staten Island</option> </select>
size 属性
multiple 属性を指定していない select 要素の size 属性に1より大きな値を指定すると単一選択型のリストボックスになります。
プルダウンリストの場合、デフォルトでは最初の項目が選択状態になりますが、単一選択型のリストボックスの場合、デフォルトではどの項目も選択されていない状態になります。
<select name="borough" size="5"> <option value="manhattan">Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens">Queens</option> <option value="bronx">Bronx</option> <option value="staten">Staten Island</option> </select>
必要に応じて option 要素に selected 属性を設定して選択状態にすることができます。単一選択型のリストボックスで複数の option 要素に selected 属性を設定すると後の方の option 要素のみが選択状態になります。
<select name="borough" size="5"> <option value="manhattan" selected>Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens">Queens</option> <option value="bronx">Bronx</option> <option value="staten">Staten Island</option> </select>
multiple 属性
select 要素に multiple 属性を指定すると、メニューの中から複数の項目を選択できる複数選択型のリストボックスになり、表示する項目の数は size 属性で指定することができます。
複数の項目を選択するには shift または command(Ctrl)キーを押しながらクリックします。
複数選択型のリストボックスの場合も単一選択型のリストボックス同様、デフォルトではどの項目も選択されていない状態になります。
<select name="borough" size="5" multiple> <option value="manhattan">Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens">Queens</option> <option value="bronx">Bronx</option> <option value="staten">Staten Island</option> </select>
必要に応じて option 要素に selected 属性を設定して選択状態にすることができます。複数選択型のリストボックスの場合、複数の option 要素に selected 属性を設定することができます。
<select name="borough" size="5" multiple> <option value="manhattan" selected>Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens" selected>Queens</option> <option value="bronx">Bronx</option> <option value="staten">Staten Island</option> </select>
optgroup 要素
optgroup 要素を利用すると、セレクトメニューの項目(option 要素)をグループ化することができます。
<select name="area" size="1"> <optgroup label="Manhattan"> <option value="uws">Upper West Side</option> <option value="ev">East Village</option> <option value="gramercy">Gramercy Park</option> <option value="les">Lower East Side</option> </optgroup> <optgroup label="Brooklyn"> <option value="williamsburg">Williamsburg</option> <option value="gp">Green Point</option> <option value="flatbush">Flatbush</option> <option value="Red Hook">Red Hook</option> </optgroup> </select>
プロパティ
select 要素はフォームコントロールなので、input 要素など他のフォームコントロールと共通のプロパティとメソッドを持っていますが、以下のような固有のプロパティやメソッドがあります。
プロパティ | 説明 |
---|---|
length | select 要素に含まれる option 要素の数 |
options | select 要素に含まれる全ての option 要素を格納した配列のようなオブジェクト |
selectedIndex | 現在選択されている option 要素を示すインデックス番号。複数選択型のリストボックスで複数の option 要素が選択されている場合は選択されている「最初」の option 要素のインデックスの値になります。-1 は要素が選択されていないことを示します。 |
selectedOptions | 選択されているすべての option 要素の集まり(配列のようなオブジェクト:HTMLCollection)。それぞれの要素にはインデックス(添字)や item() や name 属性が設定されていれば namedItem() でアクセスできます。 |
size | HTML の size 属性の値。セレクトボックスに表示される項目数。HTML で明示的に size 属性を指定していない場合は単一選択型でも複数選択型でも 0 が返ります。 |
value | 選択されている option 要素があれば最初の option 要素の value プロパティの値を返し、選択されている option 要素がなければ、空文字列を返します。選択されている option 要素に value 属性がない場合は、<option>テキスト</option> の「テキスト」の部分(option 要素の text プロパティ)を返します。 |
メソッド | 説明 |
---|---|
add() | option 要素を追加します。項目の追加・削除 |
item() | 引数で指定した位置(インデックス番号)の option 要素を取得します。 |
namedItem() | id または name 属性が設定されていれば、引数で指定した名前(id または name 属性の値)の option 要素を取得します。 |
remove() | 指定したインデックス番号の option 要素を削除します。 |
options
options プロパティではその select 要素に含まれる全ての option 要素を格納した配列のようなオブジェクト(HTMLOptionsCollection)を取得できます。
このオブジェクトは全ての option 要素の他に select 要素と同じようなプロパティやメソッド(length、electedIndex、add、remove、item、namedItem)を持っています。
それぞれの要素には添字 [n](n はインデックス番号)や item(n) や name 属性が設定されていれば namedItem(name) でアクセスできます。
以下は select 要素に含まれる全ての option 要素のインデックス番号、value 属性の値、テキストを出力する例です。
<select name="selectBox"> <option value="1">Foo</option> <option value="2">Bar</option> <option value="3">Baz</option> </select> <script> // options プロパティを取得 const opts = document.querySelector('[name="selectBox"]').options; //select 要素に含まれる全ての option 要素を for 文でループ for(let i=0; i<opts.length; i++) { console.log(`index: ${opts[i].index} value: ${opts[i].value} text: ${opts[i].text}`); } /* //出力結果 index: 0 value: 1 text: Foo index: 1 value: 2 text: Bar index: 2 value: 3 text: Baz */ </script>
以下は Chrome で options のオブジェクトプロパティを出力する例です。いくつかの options のプロパティ(add、remove、selectedIndex)は IE ではサポートされていません。
// options プロパティを取得 const opts = document.querySelector('[name="selectBox"]').options; //options プロパティ(HTMLOptionsCollection)のオブジェクトプロパティを for in ループで調査 for(let prop in opts){ console.log("プロパティ: " + prop + " 値: " + opts[prop] + "\n") } /* 出力結果 プロパティ: 0 値: [object HTMLOptionElement] //option 要素 プロパティ: 1 値: [object HTMLOptionElement] //option 要素 プロパティ: 2 値: [object HTMLOptionElement] //option 要素 プロパティ: length 値: 3 //length プロパティ プロパティ: selectedIndex 値: 0 //selectedIndex プロパティ プロパティ: add 値: function add() { [native code] } //add メソッド プロパティ: remove 値: function remove() { [native code] } //remove メソッド プロパティ: item 値: function item() { [native code] } //item メソッド プロパティ: namedItem 値: function namedItem() { [native code] } //namedItem メソッド */
参考:HTMLOptionsCollection インタフェース
option 要素のプロパティ
プロパティ | 説明 |
---|---|
defaultSelected | 初期値として選択されていたかどうかを表す真偽値(HTML の selected 属性の値) |
index | select 要素の中で何番目の option 要素であるかのインデックス番号 |
label | HTML で label 属性が設定されていればその値。設定されていない場合は、要素のテキストコンテンツ(textContent の値)。 |
selected | この要素が現在選択されているかどうかを示す真偽値 |
text | この要素のテキストコンテンツ(textContent の値) |
value | value 属性が存在する場合はその値。存在しない場合は textContent の値 |
要素の取得
select 要素の取得
select 要素がフォーム内にある場合は、 document.forms や elements を使って取得することができます。
<form name="myForm"> <select name="mySelect"> <option value="manhattan">Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens">Queens</option> <option value="bronx" selected>Bronx</option> <option value="staten">Staten Island</option> </select> </form> <script> //name 属性が myForm の form 要素内にある name 属性が mySelect の select 要素 const selectElem = document.myForm.mySelect; //以下でも同じこと ※ .forms は省略可能 //const selectElem = document.forms.myForm.mySelect; //const selectElem = document.forms['myForm'].mySelect; //const selectElem = document.forms.myForm['mySelect']; //const selectElem = document.forms.myForm.elements['mySelect']; //select 要素の value プロパティ(選択された項目の値) alert(selectElem.value); //bronx </script>
select 要素がフォーム内にない場合は(フォーム内にある場合でも)、querySelector() や getElementsByName() などの DOM のメソッドなどを使って取得することができます。
以下の例では document.querySelector() の引数に 'select[name="mySelect"]' を渡していますが、環境に応じてセレクタを指定します。
<div class="sample"> <select name="mySelect"> <option value="manhattan">Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens">Queens</option> <option value="bronx" selected>Bronx</option> <option value="staten">Staten Island</option> </select> </div> <script> //name 属性が myForm の select 要素 const selectElem = document.querySelector('select[name="mySelect"]'); //getElementsByName で取得する場合(インデックスを指定) //const selectElem = document.getElementsByName('mySelect')[0]; //select 要素の value プロパティ(選択された項目の値) alert(selectElem.value); //bronx </script>
option 要素の取得
select 要素の options プロパティで select 要素に含まれる全ての option 要素を(要素の集まりから成る配列のようなオブジェクトとして)取得することができます。
<form name="myForm"> <select name="mySelect"> <option value="manhattan">Manhattan</option> <option value="brooklyn">Brooklyn</option> <option value="queens">Queens</option> <option value="bronx" selected>Bronx</option> <option value="staten">Staten Island</option> </select> </form>
以下は select 要素にアクセスしてその全ての option 要素を options プロパティを使って取得する例です。
//select 要素を取得 const selectElem = document.myForm.mySelect; //select 要素の options プロパティで option 要素を取得 let optionElems = selectElem.options; // 以下でも同じ optionElems = document.myForm.mySelect.options; // または optionElems = document.querySelector('select[name="mySelect"]').options; alert(optionElems.length); //5
以下は options プロパティを使わずに querySelectorAll で取得する例です。
const optionElems = document.querySelectorAll('select[name="mySelect"] option'); alert(optionElems.length); //5
個々の option 要素にアクセスするには、インデックス番号や item() メソッドを使います。option 要素に name 属性が指定されていれば、namedItem() メソッドで取得することもできます。
<form name="myForm"> <select name="mySelect"> <option name="mh" value="manhattan">Manhattan</option> <option name="bk" value="brooklyn">Brooklyn</option> <option name="qs" value="queens">Queens</option> <option name="bx" value="bronx">Bronx</option> <option name="si" value="staten">Staten Island</option> </select> </form> <script> //インデックスが 0 の option 要素(selsect 要素のメソッド) let firstOption = document.myForm.mySelect.item(0); //以下でも同じ firstOption = document.myForm.mySelect[0]; //以下は上記と同じこと //options プロパティのインデックスが 0 の要素(options のメソッド) firstOption = document.myForm.mySelect.options.item(0); firstOption = document.myForm.mySelect.options[0]; console.log(firstOption.value); //manhattan //name 属性が bk の option 要素 let secondOption = document.myForm.mySelect.namedItem('bk'); console.log(secondOption.value); //brooklyn </script>
選択状態にする
select 要素の値を設定する(特定の option 要素を選択状態にする)には以下のような方法があります。
- select 要素の selectedIndex プロパティに option 要素のインデックス番号を設定する
- select 要素の value プロパティに option 要素の値を設定する
- option 要素の selected プロパティを true に設定する
以下は単一選択型の select 要素の値を設定する(特定の option 要素を選択状態にする)例で、上記のいずれの方法でも設定可能です。
単一選択型のプルダウンリストの場合、初期状態でいずれの option 要素にも selected 属性が設定されていない場合、最初の option 要素が選択されています。
select 要素に含まれる全ての option 要素は options プロパティで取得できます(25行目)。
<select name="mySelect"> <option value="foo">Foo</option> <option value="bar">Bar</option> <option value="baz">Baz</option> </select> <script> //select 要素を取得 const selectElem = document.querySelector('[name="mySelect"]'); //初期状態で selected 属性が設定されていないので最初の option 要素が選択されている console.log(selectElem.value); //foo console.log(selectElem.selectedIndex); //0 //selectedIndex を1に(インデックスが1の option 要素を選択状態に) selectElem.selectedIndex = 1; console.log(selectElem.value); //bar console.log(selectElem.selectedIndex); //1 //select 要素の value に値を設定(value が baz の option 要素を選択状態に) selectElem.value = 'baz'; console.log(selectElem.value); //baz console.log(selectElem.selectedIndex); //2 //インデックスが0の options(最初の option 要素)の selected プロパティを true に selectElem.options[0].selected = true; console.log(selectElem.value); //foo console.log(selectElem.selectedIndex); //0 </script>
複数の項目を選択状態にする
select 要素の selectedIndex や value プロパティを設定する方法では1つの要素しか選択状態にすることができません。そのため複数の項目を選択状態にするには、「option 要素の selected プロパティを true に設定する」方法を使います。
select 要素に含まれる全ての option 要素は options プロパティで取得できます。
また、「選択されている」全ての option 要素(HTMLCollection:配列のようなオブジェクト)は、select 要素の selectedOptions で取得できます。
以下は複数選択型のセレクトボックスで複数の項目(1番目と3番目)を選択状態にする例です。
<select name="mySelect" size="3" multiple> <option value="foo">Foo</option> <option value="bar">Bar</option> <option value="baz">Baz</option> </select> <script> //select 要素を取得 const selectElem = document.querySelector('[name="mySelect"]'); //初期状態では選択されている option 要素がないので、value プロパティは空文字列を返す console.log(selectElem.value); // 空 //選択されている option 要素がないので、selectedIndex プロパティは -1 を返す console.log(selectElem.selectedIndex); // -1 //options のインデックスが0と2の selected プロパティを true に selectElem.options[0].selected = true; selectElem.options[2].selected = true; //選択されているすべての option 要素の数 console.log(selectElem.selectedOptions.length); //2 //選択されているすべての option 要素の値を出力 for(let i=0; i<selectElem.selectedOptions.length; i++) { console.log(selectElem.selectedOptions[i].value); // foo baz } //select 要素の value プロパティは選択されている「最初」の option 要素の value の値 console.log(selectElem.value); //foo //selectedIndex プロパティは選択されている「最初」の option 要素のインデックスの値 console.log(selectElem.selectedIndex); //0 </script>
値の取得 value
単一選択型(プルダウンリスト)のセレクトボックスで選択されている項目(option 要素)の値を取得するには、select 要素の value プロパティを使うのが簡単です。
選択されている項目のテキストを取得するには selectedIndex や selectedOptions プロパティを使います(これらのプロパティを使えば値も取得できます)。
単一選択型の場合
select 要素の value プロパティで取得
select 要素の value プロパティは、選択されている最初の option 要素の value(値)を返すので、単一選択型セレクトボックスの選択されている項目の値を簡単に取得できます。
以下は Check ボタンをクリックすると、その時点で選択されている項目を出力する例です。
初期状態では最初の項目が選択状態になっています。最初の項目(option 要素)の value 属性は空なので、取得した select 要素の value プロパティが空であれば「項目が選択されていません」と出力するようにしています。
value:
<select name="mySelect"> <option value="">選択してください</option> <option value="manhattan">マンハッタン</option> <option value="brooklyn">ブルックリン</option> <option value="queens">クイーンズ</option> <option value="bronx">ブロンクス</option> <option value="staten">スタテンアイランド</option> </select> <button type="button" id="btn">Check</button> <p>value:<span id="output"></span></p> <script> //select 要素を取得 const selectElem = document.querySelector('select[name="mySelect"]'); //ボタンの要素 const btn = document.getElementById('btn'); //出力先の要素 const output = document.getElementById('output'); //ボタンにクリックイベントを設定 btn.addEventListener('click', ()=> { //select 要素の value プロパティを取得 const val = selectElem.value; //value プロパティの値が空でなければ値を出力 if(val !=="") { //出力先のテキストに select 要素の value プロパティを設定 output.textContent = val; }else{ //値が空の場合は以下を出力 output.textContent = "項目が選択されていません"; } }); </script>
selectedIndex プロパティ
select 要素の selectedIndex プロパティには現在選択されている option 要素を示すインデックス番号が入っています。
selectedIndex プロパティの値を使えば、選択されている <option>〜</option> の「〜」の部分を取得することができます。
select 要素に含まれる全ての option 要素は select 要素の options プロパティで取得でき、各 option 要素にはそのインデックス番号でアクセスできます。
また、option 要素のテキストは option 要素の text プロパティで取得できます。
text:
<select name="mySelect"> <option value="">選択してください</option> <option value="manhattan">マンハッタン</option> <option value="brooklyn">ブルックリン</option> <option value="queens">クイーンズ</option> <option value="bronx">ブロンクス</option> <option value="staten">スタテンアイランド</option> </select> <button type="button" id="btn">Check</button> <p>text:<span id="output"></span></p> <script> //select 要素を取得 const selectElem = document.querySelector('select[name="mySelect"]'); //ボタンの要素 const btn = document.getElementById('btn'); //text の出力先の要素 const output = document.getElementById('output'); //ボタンにクリックイベントを設定 btn.addEventListener('click', ()=> { //select 要素の selectedIndex プロパティを取得 const index = selectElem.selectedIndex; //選択されている option 要素の text プロパティを取得(値を取得するには value を指定) const text = selectElem.options[index].text; //出力先に取得したテキストを設定 output.textContent = text; //上記は以下のように1行にまとめることができます //output.textContent = selectElem.options[selectElem.selectedIndex].text; }); </script>
上記の24行目では option 要素は select 要素の options プロパティを使ってアクセスしていますが、以下のようにインデックス番号や item() メソッドを使ってアクセスすることもできます。
上記の場合、以下はいずれも同じことです。
//select 要素の options プロパティにインデックス番号を指定 const text = selectElem.options[index].text; //select 要素にインデックス番号を指定 const text = selectElem[index].text; //select 要素の item() メソッドにインデックス番号を指定 const text = selectElem.item(index).text;
selectedOptions プロパティ
selectedOptions プロパティは「選択されている」全ての option 要素を含む配列のようなオブジェクトで、このプロパティを使って選択されている option 要素の value や text を取得することもできます。
※ selectedOptions は IE では未対応です。
単一選択型の場合、選択されている option 要素は1つですが、selectedOptions プロパティが返す値は配列(のようなオブジェクト)なので、先頭の要素 [0] を取得します。
以下は selectedOptions プロパティを使って選択されている項目のテキストを取得する例です。
<select name="mySelect"> <option value="">選択してください</option> <option value="manhattan">マンハッタン</option> <option value="brooklyn">ブルックリン</option> <option value="queens">クイーンズ</option> <option value="bronx">ブロンクス</option> <option value="staten">スタテンアイランド</option> </select> <button type="button" id="btn">Check</button> <p>text:<span id="output"></span></p> <script> //select 要素を取得 const selectElem = document.querySelector('select[name="mySelect"]'); //ボタンの要素 const btn = document.getElementById('btn'); //text の出力先の要素 const output = document.getElementById('output'); //ボタンにクリックイベントを設定 btn.addEventListener('click', ()=> { //selectedOptions プロパティの先頭の要素(インデックス番号が0の要素)が選択されている要素 const selectedOption = selectElem.selectedOptions[0]; //選択されている option 要素の text プロパティを取得(値を取得するには value を指定) const text = selectedOption.text; //出力先に取得したテキストを設定 output.textContent = text; //上記は以下のように1行にまとめることができます //output.textContent = selectElem.selectedOptions[0].text; }); </script>
複数選択型の場合
select 要素の value や selectedIndex プロパティが返すのは、「最初の」 option 要素の値(1つだけ)なので、それらを使って選択されている「複数の値」を取得するができません。
複数選択型の場合、選択されている「複数の値」を取得するには以下のような方法があります。
- select 要素の selectedOptions プロパティを使う(※ IE は未対応)
- select 要素の options プロパティや全ての option 要素の選択状態を調べる
- :checked 擬似クラスを使ったセレクタを querySelectorAll() に指定する
selectedOptions プロパティを使う
以下は複数選択型のセレクトボックスで、Check ボタンをクリックすると選択されている全ての項目の value の値と選択されている項目数を出力する例です。
選択されている全ての option 要素は select 要素の selectedOptions プロパティで取得して、for 文で全ての値を取得しています。
Clear ボタンをクリックすると、選択されている全ての option 要素の selected プロパティに false を設定して選択を解除しています。また、その際に現在選択されている項目を示す selectedIndex プロパティに -1 を設定して現在選択されている項目もクリアしています。
value:
length:
<select name="mySelect" size="5" multiple> <option value="manhattan">マンハッタン</option> <option value="brooklyn">ブルックリン</option> <option value="queens">クイーンズ</option> <option value="bronx">ブロンクス</option> <option value="staten">スタテンアイランド</option> </select> <button type="button" id="btn">Check</button> <button type="button" id="clear">Clear</button> <p>value:<span id="outputValue"></span></p> <p>length:<span id="outputLength"></span></p> <script> //select 要素を取得 const selectElem = document.querySelector('select[name="mySelect"]'); //value の出力先の要素 const outputValue = document.getElementById('outputValue'); //length の出力先の要素 const outputLength = document.getElementById('outputLength'); //Check ボタンにクリックイベントを設定 document.getElementById('btn').addEventListener('click', ()=> { //select 要素の selectedOptions プロパティで、選択されている option 要素を全て取得 const selected = selectElem.selectedOptions; //選択された option 要素の値を格納する配列 const selectedValues = []; //for 文で各要素の value プロパティを配列に追加 for(let i=0; i<selected.length; i++) { selectedValues.push(selected[i].value); } //選択された option 要素の値をスペース区切りで繋げて出力 outputValue.textContent = selectedValues.join(' '); //選択された option 要素の数を出力 outputLength.textContent = selected.length; }); //Clear ボタンにクリックイベントを設定 document.getElementById('clear').addEventListener('click', ()=> { //select 要素の selectedOptions プロパティで選択されている option 要素を全て取得 const selected = selectElem.selectedOptions; for(let i=0; i<selected.length; i++) { //選択されている option 要素の selected プロパティを false にして選択を解除 selected[i].selected = false; } //上記の代わりに以下でも同じ結果が得られます(selectedOptions の要素を削除) //selectElem.selectedOptions.length = 0; //select 要素の selectedIndex プロパティに -1 を指定して何も選択されていない状態に selectElem.selectedIndex = -1; //出力をクリア outputValue.textContent = ""; outputLength.textContent = ""; }); </script>
IE にも対応するには、options プロパティの各要素の selected プロパティを調べます。
以下は上記の Check ボタンのイベント登録の部分(10〜23行目)を selectedOptions を使わずに書き換えた例です。
document.getElementById('btn').addEventListener('click', ()=> { //select 要素の options プロパティで全ての option 要素を取得 const opts = selectElem.options; //選択された option 要素の値を格納する配列 const selectedValues = []; //for 文で各要素の selected プロパティを調べる for(let i=0; i<opts.length; i++) { if(opts[i].selected) { //selected プロパティが true であれば配列に追加 selectedValues.push(opts[i].value); } } outputValue.textContent = selectedValues.join(' '); //要素の値を格納する配列の長さが選択された要素の数 outputLength.textContent = selectedValues.length; });
:checked 擬似クラス
:checked はラジオボタンやチェックボックス、オプション項目 (option 要素) がチェックされた場合に適用される CSS の擬似クラスです。
ラジオボタンやチェックボックス同様、:checked 擬似クラスを使ったセレクタを querySelectorAll() に指定して、選択された項目を取得することができます。
以下は セレクタ option:checked を querySelectorAll() に指定して選択された項目の全てを取得して、それらのテキストを出力する例です。
text:
<select name="mySelect" size="5" multiple> <option value="manhattan">マンハッタン</option> <option value="brooklyn">ブルックリン</option> <option value="queens">クイーンズ</option> <option value="bronx">ブロンクス</option> <option value="staten">スタテンアイランド</option> </select> <button type="button" id="btn">Check</button> <button type="button" id="clear">Clear</button> <p>text:<span id="outputText"></span></p> <script> //value の出力先の要素 const outputText = document.getElementById('outputText'); //Check ボタンにクリックイベントを設定 document.getElementById('btn').addEventListener('click', ()=> { //option:checked をセレクタに指定して選択されている option 要素を全て取得 const selectedElems = document.querySelectorAll('[name="mySelect"] option:checked'); //選択された option 要素のテキストを格納する配列 const selectedText = []; //for 文で各要素の text プロパティ(テキスト)を配列に追加 for(let i=0; i<selectedElems.length; i++) { selectedText.push(selectedElems[i].text); } outputText.textContent = selectedText.join(' '); }); //select 要素を取得 const selectElem = document.querySelector('select[name="mySelect"]'); //Clear ボタンにクリックイベントを設定 document.getElementById('clear').addEventListener('click', ()=> { //選択されている option 要素の選択を解除 selectElem.selectedOptions.length = 0; selectElem.selectedIndex = -1; outputText.textContent = ""; }); </script>
上記の例では :checked 擬似クラスを使って選択された項目の背景色をオレンジにしています。
select[name="mySelect"] option:checked { background-image: linear-gradient(0deg, orange 0%, orange 100%); } /* background-color では適用されないので background-image を使用 */
但し、option 要素は置換要素として扱われるため、:checked でスタイルが適用される部分はブラウザにより異なり、上記の背景色変更の設定(CSS スタイル)は Safari などでは機能しません。
項目の追加・削除
セレクトボックスの項目(option 要素)を追加するには select 要素の add() メソッドを使います。
add() メソッドは引数に追加する option 要素とその位置(オプション)を指定します。第2引数に指定したインデックス番号または要素の前に option 要素が追加されます。
第2引数を省略または null を指定した場合は最後の位置に追加されます。
以下は新たにセレクトボックスを作成して既存の div 要素に追加する例です。
createElement() で select 要素と option 要素を生成し、option 要素には value 属性とテキストを設定して add() メソッドで select 要素に追加しています。最後に作成した select 要素を既存の div 要素に追加しています。
add() メソッドの第2引数に null を指定しているので option 要素の最後に追加されます(この場合第2引数を省略しても同じ)。
<div id="foo"></div> <script> //select 要素を生成 const selectElem = document.createElement('select'); //2つの option 要素を生成 const opt1 = document.createElement('option'); const opt2 = document.createElement('option'); //option 要素の value 属性を設定 opt1.value = "1"; //option 要素の text(テキスト)を設定 opt1.text = "Option 1"; opt2.value = "2"; opt2.text = "Option 2"; //select 要素に option 要素を追加 selectElem.add(opt1, null); //add(opt1) でも同じ selectElem.add(opt2, null); //add(opt2) でも同じ //既存の id が foo の div 要素に生成した select 要素を追加 document.getElementById('foo').appendChild(selectElem); </script>
<div id="foo"> <select> <option value="1">Option 1</option> <option value="2">Option 2</option> </select> </div>
option 要素を作成するコンストラクタ
option 要素を作成するためのコンストラクタ Option() が用意されています。
let option = new Option(text, value, defaultSelected, selected);
引数 | 意味 |
---|---|
text | 表示するテキスト。省略した場合は空文字列("") |
value | value 属性の値。省略した場合は text の値 |
defaultSelected | selected 属性を指定するかどうかの真偽値。省略した場合は false |
selected | 選択状態を設定する真偽値。既定値は false (未選択) |
以下は Option() を使って option 要素を生成する例です。
const opt1 = new Option('Option 1', '1', true, true); //上記は以下と同じこと const opt1 = document.createElement("option"); opt1.text = "Option 1"; opt1.value = "1"; opt1.defaultSelected = true; opt1.selected = true; //以下のような option 要素が生成される <option value="1" selected="">Option 1</option>
以下は既存の select 要素に option 要素を追加する例です。
<select name="mySelect"> <option value="1">Option 1</option> <option value="2">Option 2</option> </select> <script> //select 要素を取得 const mySelect = document.querySelector('[name="mySelect"]'); //追加する option 要素を生成 const opt0 = new Option(' --- ', '', true, true); const opt3 = new Option('Option 3', '3'); //生成した opt0 を option 要素の先頭に追加 mySelect.add(opt0, 0); //または mySelect.add(opt0, mySelect.options[0]); //生成した opt0 を option 要素の末尾に追加 mySelect.add(opt3); </script> <!-- 上記の結果 --> <select name="mySelect"> <option value="" selected=""> --- </option> <option value="1">Option 1</option> <option value="2">Option 2</option> <option value="3">Option 3</option> </select>
項目の削除 remove()
項目(option 要素)を削除するには remove() メソッドの引数にインデックス番号を指定します。
<select name="mySelect"> <option value="" selected=""> --- </option> <option value="1">Option 1</option> <option value="2">Option 2</option> <option value="3">Option 3</option> </select> <script> //select 要素を取得 const mySelect = document.querySelector('[name="mySelect"]'); //最初の option 要素を削除 mySelect.remove(0); //残りの option 要素の3番目を削除 mySelect.remove(2); </script> <!-- 上記の結果 --> <select name="mySelect"> <option value="1">Option 1</option> <option value="2">Option 2</option> </select>
イベント
セレクトボックスでは項目を選択する際に input 及び change イベントが発生します。
input イベントは要素の値が変更されるたびに発生し、change イベントは要素の変更が終わったときに発生しますが、セレクトボックスの場合は項目が選択される際にほぼ同時に発生します(input イベントの方が先に発生します)。
以下は単一選択型のセレクトボックスで、項目を選択するとその値とテキストを出力する例です。
value:
text:
この例では change イベントを使っていますが、input イベントでもほぼ同じ結果になります。
addEventListener() でアロー関数を使う場合、リスナーを登録した要素はイベントの currentTarget プロパティで取得できます。
select 要素の value プロパティには、選択された option 要素の値(value)が入っています。
選択された要素のテキストを取得するには、選択された要素のインデックスを selectedIndex で取得して、options にインデックスを指定して選択された option 要素を取得し、text を取得します。
<select name="mySelect"> <option value="">選択してください</option> <option value="manhattan">マンハッタン</option> <option value="brooklyn">ブルックリン</option> <option value="queens">クイーンズ</option> <option value="bronx">ブロンクス</option> <option value="staten">スタテンアイランド</option> </select> <p>value: <span id="valueOut"></span></p> <p>text: <span id="textOut"></span></p> <script> //select 要素を取得 const selectElem = document.querySelector('select[name="mySelect"]'); //value の出力先の要素 const valueOut = document.getElementById('valueOut'); //text の出力先の要素 const textOut = document.getElementById('textOut'); selectElem.addEventListener('change', (e) => { //リスナーを登録した select 要素を取得 const elem = e.currentTarget; //select 要素の value プロパティ(選択されている option 要素の value) valueOut.textContent = elem.value //selectedIndex を options のインデックスに指定して選択されている要素を取得 textOut.textContent = elem.options[elem.selectedIndex].text; //この場合リスナーを登録した要素とイベントが発生する要素は同じ //console.log(e.currentTarget === e.target); //true }); </script>
addEventListener() で function 文を使う場合、リスナーを登録した要素は this で取得できるので、以下のように記述しても同じです。
selectElem.addEventListener('change', function() { valueOut.textContent = this.value textOut.textContent = this.options[this.selectedIndex].text; });
以下は複数選択型のセレクトボックスで、項目を選択するとそれらの値とテキストを出力する例です。
value:
text:
以下の例では selectedOptions を使って選択されている要素を取得しています。
<select name="mySelect" size="5" multiple> <option value="manhattan">マンハッタン</option> <option value="brooklyn">ブルックリン</option> <option value="queens">クイーンズ</option> <option value="bronx">ブロンクス</option> <option value="staten">スタテンアイランド</option> </select> <p>value: <span id="valueOut"></span></p> <p>text: <span id="textOut"></span></p> <script> //select 要素を取得 const selectElem = document.querySelector('select[name="mySelect"]'); //value の出力先の要素 const valueOut = document.getElementById('valueOut'); //text の出力先の要素 const textOut = document.getElementById('textOut'); selectElem.addEventListener('change', (e) => { //リスナーを登録した select 要素を取得 const elem = e.currentTarget; //選択された option 要素の値を格納する配列 const selectedValues = []; //選択された option 要素のテキストを格納する配列 const selectedText = []; //selectedOptions で選択されている option 要素を全て取得 const selected = elem.selectedOptions; //選択されている option 要素の値とテキストを取得して配列に追加 for(let i=0; i<selected.length; i++){ selectedValues.push(selected[i].value); selectedText.push(selected[i].text); } //選択されている option 要素の値をスペース区切りで出力 valueOut.textContent = selectedText.join(' '); //選択されている option 要素のテキストをスペース区切りで出力 textOut.textContent = selectedValues.join(' '); }); </script>
以下は上記と同じことを selectedOptions プロパティを使わず、options で全ての option 要素を取得して、その selected プロパティを調べる例です。
selectElem.addEventListener('change', (e) => { const elem = e.currentTarget; const selectedValues = []; const selectedText = []; //options で全ての option 要素を取得 const opts = elem.options; //それぞれの option 要素を調べて選択状態であれば値とテキストを取得して配列に追加 for(let i=0; i<opts.length; i++){ //selected が true であれば選択されている if(opts[i].selected) { selectedValues.push(opts[i].value); selectedText.push(opts[i].text); } } valueOut.textContent = selectedText.join(' '); textOut.textContent = selectedValues.join(' '); });
項目を動的に生成
以下は2つのセレクトボックスがあり、最初のセレクトボックスの選択された項目により、2つ目のセレクトボックスの項目を動的に生成する例です。
最初のプルダウンメニューの最初の項目(選択してください)は選択できないように disabled 属性を指定し、初期状態で表示されるように selected 属性を指定しています。
2つ目のプルダウンメニューは、最初のプルダウンメニューで項目が選択された際に項目を選択するように初期状態では select 要素自体に disabled 属性を指定しています。
2番目のプルダウンメニューに表示する項目のデータ(subCategoryList)はキーに1番目の select 要素の各 option 要素の value を、値にその option 要素が選択された場合に表示する項目の配列を設定したオブジェクト(連想配列)になっています。
それぞれの select 要素を取得して変数に代入し、最初の name="category" の select 要素に change イベントのリスナーを登録しています。
リスナー関数では、2番目のプルダウンメニューの disabled 属性を解除し、一度全ての項目を削除して空にしています。そして、1番目のプルダウンメニューで選択された値を使って表示する項目のデータを取得し、option 要素を生成し select 要素に追加しています。
1番目のプルダウンメニューで選択された値が、2番目のプルダウンメニューに表示する項目のデータ(オブジェクト)のキーになっているので、キーを指定することで表示する項目の配列を取得できます。
項目の配列を取得したら、forEach() で配列のそれぞれの要素をテキストとした option 要素を生成し、select 要素に追加することで表示しています。
<select name="category"> <option disabled selected>選択してください</option> <option value="wine">ワイン</option> <option value="sake">日本酒</option> <option value="beer">ビール</option> </select> <select name="subCategory" disabled> <option disabled selected>種類</option> </select> <script> //subCategory の select 要素に表示する項目のデータ const subCategoryList = { "wine": ["スティル", "スパークリング", "フォーティファイド", "フレーヴァード"], "sake": ["純米酒", "本醸造酒", "吟醸酒"], "beer": ["ラガー", "エール"] }; //select 要素を取得 const category = document.querySelector('select[name="category"]'); const subCategory = document.querySelector('select[name="subCategory"]'); category.addEventListener('change', () => { //subCategory の disabled を解除 subCategory.disabled = false; //subCategory の option を削除(options の length を0にして内容を削除) subCategory.options.length = 0; //subCategory の最初の option 要素を作成 const firstOption = document.createElement('option'); firstOption.text = '種類を選択してください'; firstOption.defaultSelected = true; firstOption.disabled = true; //subCategory に上記で作成した option 要素を追加 subCategory.add(firstOption); //category の項目(option 要素)で選択された値を取得 const selected = category.value; //上記 selected をキーに指定して表示する項目のデータを取得して各値につき option 要素を生成 subCategoryList[selected].forEach( (item) => { let option = document.createElement('option'); //option 要素のテキストにデータの値を設定 option.text = item; //subCategory に option 要素を追加 subCategory.add(option); }); }); </script>