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

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

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

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

3回答

3634閲覧

jqueryのfor文を使った繰り返しが上手くいきません。

heroherohero

総合スコア38

JavaScript

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

1クリップ

投稿2017/03/07 04:03

###前提・実現したいこと
jqueryのfor文を使った繰り返しが上手くいきません。
実現したいこととしては、phpの方で指定しているボタン(id=check_buton+0からnumberOfQuestion番目までの番号)ごとに、指定している要素(class=v+0からnumberOfQuestion番目までの番号)の末尾にhtmlの要素を追加するということを実現したいです。
ですが、思ったように、動作してくれません。
下記のコードだと、
phpの方で指定しているボタンは、全て動作しますが、
変数のclassName=v9になっているようで、思ったように動作しません。お手数ですが、どなたか解決方法が分かる方がいらっしゃいましたら、教えていただけると幸いです。
よろしくお願いいたします。

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

<script> var numberOfQuestions = <?php echo $NumberOfQuestions; ?>; $(function () { for (var i = 0; i < numberOfQuestions; i++) { var className = 'v' + i; var checkButton = 'check_button' + i; $('#' + checkButton).click(function () { $('.' + className).after('<img src=\'../img/img/img\' width=\'30\' height=\'30\'>'); }); } }); </script>

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

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

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

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

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

guest

回答3

0

ベストアンサー

原因

for 文中でイベントハンドラ関数を定義した場合、外のスコープの変数はイベントハンドラが実行された時の値になります。
イベントハンドラが実行されたタイミングでは for ループは終了していますので、仮に numberOfQuestions === 5 であった場合、どのチェックボタンをクリックしても下記コードのように .v4 に対してimg要素ノードが挿入されることになります。

JavaScript

1$('.v4').after('<img src=\'../img/img/img\' width=\'30\' height=\'30\'>');

問題の根本は下記スレッドが参考になると思います。

質問のコードの場合、「#check_button1 -> .v1」の相関関係が成立しますので、クリックした時に event.currentTarget.id を元に className を算出するか、上記スレッドのようにクロージャや data-* 属性に対応する className を閉じ込めれば解決できるでしょう。
jQuery を使っているので event.data に閉じ込める方法も有ります。

[対策1] イベントハンドラ関数内で対象を算出する

JavaScript

1'use strict'; 2jQuery('[id^="show-image-child-"').on('click', function (event) { 3 jQuery('.' + event.currentTarget.id.replace(/-child(?=-)/, '-parent')).after('<img src="../img/img/img" width="100" height="30" alt="content" />'); 4});

[対策2] addEventListener の listener オブジェクトに閉じ込める

JavaScript

1'use strict'; 2document.querySelectorAll('[id^="show-image-child-"').forEach(function (input) { 3 input.addEventListener('click', { 4 parent: jQuery('.' + input.id.replace(/-child(?=-)/, '-parent')), 5 handleEvent: function handleClick () { 6 this.parent.after('<img src="../img/img/img" width="100" height="30" alt="content" />'); 7 } 8 }, false); 9});

[対策3] クロージャに閉じ込める

JavaScript

1'use strict'; 2jQuery('[id^="show-image-child-"').each(function (i, input) { 3 var parent = jQuery('.' + input.id.replace(/-child(?=-)/, '-parent')); 4 5 jQuery(input).on('click', function () { 6 parent.after('<img src="../img/img/img" width="100" height="30" alt="content" />'); 7 }); 8});

[対策4] jQuery の event.data に閉じ込める

JavaScript

1'use strict'; 2function handleClick (event) { 3 event.data.parent.after('<img src="../img/img/img" width="100" height="30" alt="content" />'); 4} 5 6for (var i = 1; i < 6; ++i) { 7 jQuery('#show-image-child-' + i).on('click', {parent: jQuery('.show-image-parent-' + i)}, handleClick); 8}

Re: tmng さん

投稿2017/03/07 04:20

編集2017/03/07 05:30
think49

総合スコア18162

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

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

heroherohero

2017/03/07 05:28 編集

コメントありがとうございました。 for 文中でイベントハンドラ関数を定義した場合、外のスコープの変数はイベントハンドラが実行された時の値になるということを知らなかったです。 おかげさまで、解決することができました。 data-*を使って、問題を解決しました。 ありがとうございました!
think49

2017/03/07 05:33

入れ違いになりましたが、対策コード(4点)を追記しました。 質問のコードには、要素の数だけイベントハンドラが増殖する為、メモリを必要以上に消費する問題があります。 同じ関数を使いまわすか、一度に全要素のイベント定義する事でメモリ消費量を最小限にできます。 https://jsfiddle.net/qg9cf4de/3/https://jsfiddle.net/qg9cf4de/4/ を比較すると分かりやすいかもしれません。
guest

0

for文を使わなくても、下記で同じようなことができます。

javascript

1var $check = ('[id^=check_button]'); 2 3$check.on('click', function () { 4 var $this = $(this), // クリックした対象の取得 5 i = $check.index($this) + 1, // 番号の取得(0からの連番でいいなら1を足さなくてよい) 6 className = 'v' + i; 7 8 $('.' + className).after('<img src="../img/img/img" width="30" height="30">'); 9});

投稿2017/03/07 05:00

yamato_hikawa

総合スコア2092

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

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

heroherohero

2017/03/07 05:27

コメントありがとうございます。 先に、コメントをいただいた方のを試したところ、実現することができました! せっかくコメントをいただいたのに、組み込めずに申し訳ございません。 また、機会がありましたら、教えていだけますと幸いです。 ありがとうございました。
yamato_hikawa

2017/03/07 05:38

カスタムデータ属性の方がわかりやすいので良いと思います。
guest

0

僕の場合は、id=check_buttonと指定しているボタンタグに、 data-checkを設定しました。

<script> /*「v」ボタンを選択したら,Ⅴマークを追加する.*/ var numberOfQuestions = <?php echo $resultForNumberOfQuestions; ?>; $(function () { for (var i = 0; i < numberOfQuestions; i++) { var checkButton = 'check_button' + i; $('#' + checkButton).click(function () { var className = $(this).data('check'); $('.' + className).children().after('<img src=\'../img/v_gray.png\' width=\'30\' height=\'30\'>'); }); } }); </script>

投稿2017/03/07 05:30

heroherohero

総合スコア38

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問