目次
forループの中の「on」ブロック内のfunction()が正しく動かない
やろうとしたのは。
これで「表示1」ボタンを押したら、「表示1」にする。
「表示2」ボタンを押したら、「表示2」にする。
それだけのことです。
こんなHTMLでボタンとダイアログを定義します。
<body> <button id="btn_open1">表示1</button> <div id="modal1" class="modal"> <div id="modal_content1" class="modal_content"> <p>表示1</p> </div> </div> <button id="btn_open2">表示2</button> <div id="modal2" class="modal"> <div id="modal_content2" class="modal_content"> <p>表示2</p> </div> </div> </body>
これで普通のjQueryで書くとこんな感じで、これは意図通りに動きます。
$(function(){ $("#btn_open1").on('click', function() { $('#modal1').show(); }); $($('#modal1')).on('click', function(event) { if(!($(event.target).closest($('#modal_content1')).length)){ $('#modal1').hide(); } }); $("#btn_open2").on('click', function() { $('#modal2').show(); }); $($('#modal2')).on('click', function(event) { if(!($(event.target).closest($('#modal_content2')).length)){ $('#modal2').hide(); } }); });
でも、ボタンの数だけ処理を書くのは、どうもよろしくない。
今回問題があったJavaScript
そう考えて、1・2の部分を変数にしてループで定義すれば、ボタンが増えても簡単に処理が追加できると考えて、以下のようにします。
$(function(){ var arr = [1,2]; for(var key in arr){ $('#modal' + arr[key]).hide(); $("#btn_open" + arr[key]).on('click', function() { $('#modal' + arr[key]).show(); }); $($('#modal' + arr[key])).on('click', function(event) { if(!($(event.target).closest($('#modal_content' + arr[key])).length)){ $('#modal' + arr[key]).hide(); } }); } });
ところが、こうすると、どちらのボタンを押しても、同じダイアログしか表示されなくなるというのが、今回の問題です。
問題の原因
forループの中にある「on」ブロックは、ループが全て終了してから実行されるというJavaScriptの仕様によって、上記の問題はおきてます。
なので、上記の書き方では、そもそも意図した処理順にならないようです。
対処方法は2通りあります。
対処方法(1)
forループの変数定義で、varをletに変更するだけです。
$(function(){ var arr = [1,2]; for(let key in arr){ $('#modal' + arr[key]).hide(); $("#btn_open" + arr[key]).on('click', function() { $('#modal' + arr[key]).show(); }); $($('#modal' + arr[key])).on('click', function(event) { if(!($(event.target).closest($('#modal_content' + arr[key])).length)){ $('#modal' + arr[key]).hide(); } }); } });
for(let key in arr)の部分ですね。
関数スコープのvarと違い、letはブロックスコープになので、何気に正しく動きます。
対処方法(2)
ちゃんとした対処方法はこちらです。
ループブロックの中の処理を即時関数で囲ってやります。
$(function(){ var arr = [1,2]; for(var keya in arr){ (function(key){ $('#modal' + arr[key]).hide(); $("#btn_open" + arr[key]).on('click', function() { $('#modal' + arr[key]).show(); }); $($('#modal' + arr[key])).on('click', function(event) { if(!($(event.target).closest($('#modal_content' + arr[key])).length)){ $('#modal' + arr[key]).hide(); } }); })(keya); } });
ループカウンタを即時関数の引数にしてるのがミソです。
どちらの方法でも、いちおう、意図通りの動作にはなりました。
めでたし。
めでたし・・です。
ではでは。