質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

396閲覧

getElementsByTagNameで取得した要素に対するforの挙動

taikiarakaki

総合スコア9

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2017/07/25 08:53

###前提・実現したいこと
javascript初学者です。
テキストボックスに日付っぽい文字列を入力してもらうため、フォーカスが外れたら正規表現の判定をするような仕組みを作りました。
コードを簡潔にすべく以下のような感じです。

###該当のソースコード

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> .dateError{ display:none; color:red; } </style> </head> <body> <form> <p><input type="text" placeholder="yyyy/mm/dd"><span class="dateError">違うよ</span></p> <p><input type="text" placeholder="yyyy/mm/dd"><span class="dateError">違うよ</span></p> <p><input type="text" placeholder="yyyy/mm/dd"><span class="dateError">違うよ</span></p> </form> <script> (function(){ "use strict" var Dates=document.getElementsByTagName("input"), DateErrors=document.getElementsByClassName("dateError"); function AE(i){ Dates[i].addEventListener("blur",function(){ if(this.value.match(/^\d{4}\/\d{2}\/\d{2}$/)){ DateErrors[i].style.display="none"; } else{ DateErrors[i].style.display="inline"; } }); } AE(0); AE(1); AE(2); })(); </script> </body> </html>

###発生している問題・エラーメッセージ
function AEに0~2を入れているので、これをforで回そうとしたらエラーとなります。

for(var i=0; i<=2; i++){ Dates[i].addEventListener("blur",function(){ if(this.value.match(/^\d{4}\/\d{2}\/\d{2}$/)){ DateErrors[i].style.display="none"; } else{ DateErrors[i].style.display="inline"; } }); }

いわく、

Uncaught TypeError: Cannot read property 'style' of undefined at HTMLInputElement.<anonymous>

###試したこと・疑問
質問のためこのような流れで説明しましたが、もともとはforでやってみたらうまくいかなくて、関数で試してみたらなぜか動いたという状況です。
なぜforでは動かないのか?
エラーの内容だとDateErrors[i]が定義されてないということのようですが、それだと関数の場合にはなぜちゃんと動くのか?
そのような疑問から質問させていただきました。

基礎知識不足は承知の上ですが、何卒ご教授いただければ幸いです。
よろしくお願いします。

###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

for + addEventListener

原因は既に指摘されているように「blur イベントが発火した時点で変数 i === 3 が成立してしまっているから」ですね。

対策として変数 i を束縛する方法があります。
方法はいくつかありますが、以下は一例。

HTML

1<form> 2 <p><input type="text" placeholder="yyyy/mm/dd"><span class="dateError">違うよ</span></p> 3 <p><input type="text" placeholder="yyyy/mm/dd"><span class="dateError">違うよ</span></p> 4 <p><input type="text" placeholder="yyyy/mm/dd"><span class="dateError">違うよ</span></p> 5</form> 6<script> 7'use strict'; 8function handleBlur (event) { 9 dateErrors[this.i].style.display = /^\d{4}\/\d{2}\/\d{2}$/.test(event.currentTarget.value) ? 'none' : 'inline'; 10} 11 12var dates = document.getElementsByTagName("input"), 13 dateErrors=document.getElementsByClassName("dateError"); 14 15for (var i = 0; i < 3; i++) { 16 dates[i].addEventListener("blur", {i: i, handleEvent: handleBlur}, false); 17} 18</script>

元のコードに出来るだけ合わせましたが、この場合は span 要素ノードを束縛したり、nextSibling で該当要素ノードを指定するのがスマートだと思います。
変数 dates, dateErrors はどちらも live な為、要素ノードの追加/削除が行われた場合にインデックス値がずれるという問題があります。

nextSibling

nextSibling を利用したコード。

addEventListener の第三引数

最近のブラウザでは問題ありませんが、旧来の仕様では第三引数は省略可能な引数ではありませんでした。
後方互換性の為に第三引数は省略しない事をお勧めします。

Re: taikiarakaki さん

投稿2017/07/25 09:51

編集2017/07/25 12:22
think49

総合スコア18164

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taikiarakaki

2017/07/25 10:21

発展的なご回答、ありがとうございます。 発展的! すごいです。身に余るご回答で全然理解できていませんが、取り急ぎお礼申し上げ、熟読の上でご教授いただいた方法を試してみます。 また、addEventListener の第三引数についてもご指摘ありがとうございます。「とりあえず動く」程度の理解でやってましたが、きちんと調べてみます。 余談ですが、浅い部分的な知識で楽しようとした結果、皆様にお手数をおかけして申し訳ない気持ちです。同時に初めての質問で的確なご回答頂き、非常に勇気づけられました。 今後とも学習に励んでいこうと思います。
guest

0

forを使って書くと、iが同じものに紐付いてしまうので、イベントが実行されるときには**ループを抜けきったあとのi = 3**が使われてしまい、エラーとなります。

関数を使ったときは、iが関数の実行ごとに別物となるので、ループで変わってしまう、ということもありません。

投稿2017/07/25 09:08

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taikiarakaki

2017/07/25 09:40

早速のご回答、ありがとうございます! なるほど、forだとそのようなことになっていたのですね。 正直に言うと完全な理解には至っていませんが、ご回答を胸に秘めつつ学習を進めていこうと思います。 (基礎知識を底上げし、あの回答はこういうことだったのか!と腑に落ちるその時まで)
guest

0

ベストアンサー

forのほうを書き換えると下記のようにかけます。(変数が1つ増える意外同じ挙動です)

JavaScript

1var i; // 「A」 2var func = function(){ 3 if(this.value.match(/^\d{4}\/\d{2}\/\d{2}$/)){ 4 DateErrors[i].style.display="none"; // 「i」は「A」の部分で宣言したものを参照している 5 } 6 else{ 7 DateErrors[i].style.display="inline"; 8 } 9} 10for( i=0; i<=2; i++){ // forを抜けるには「i」が「3」以上 11 Dates[i].addEventListener("blur",func); 12} 13// この時点で「i」は「3」 14 15// クリックイベントはこれ以降に起こるため、Dates[3]となってエラーになる。

投稿2017/07/25 09:33

kei344

総合スコア69407

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taikiarakaki

2017/07/25 09:47

丁寧なご回答、ありがとうございます。 腑に落ちました! 奥が深いですね…。私の理解が浅いのか…。 ご回答を胸に刻んで学習を進めてまいります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問