- 締切済み
ループ内のaddeventlistner
javascript初心者です、いろいろ検索したのですがわからず 教えてください。 サンプル <div id="hoge"></div> <script type=application/javascript> window.onload=function () { var html="検索エンジンのビッグ3" var big3= [ { "name":"google", "url":"http://google.com" }, { "name":"yahoo!", "url":"http://yahoo.com" }, { "name":"bing", "url":"http://bing.com" } ]; for (var i = 0, len = big3.length; i < len; i++) { html+= "<br />名前:"+big3[i].name+"<br />"; html+= "URL:"+big3[i].url+"<br />"; html+= '<input type="button" id="btn" value="投票" /><br />' }; document.getElementById("hoge").innerHTML=html; } </script> ----サンプルここまで このように配列をずらずらっと表示させてそれぞれのボタンを押すと、 その時の配列の情報を参照したいのです。 下のコードをボタンのすぐ下に置きましたが、cannot call method addEventListener of nullってエラーでできず、for文の外だと配列情報がとれず、基礎がわかっておらずすみませんが教えてください。 document.getElementById("btn").addEventListener('click',function(){alert("あなたがおしたのは"+big3[i].name)},false);
- みんなの回答 (8)
- 専門家の回答
みんなの回答
- babu_baboo
- ベストアンサー率51% (268/525)
think49 さん、 ほそく、ありがとうございます。 >「Function#bind を使いましょー」 そそっ。 (document にぞくすまえに、いべんとをはりつけたから?) -- > 簡潔に書けたりします? う~ん、かんがえてたら、はたしてこれが「よいさんぷる」なのか?! (しつもんしゃを、おきざりにした感。ごめんなさい) <!DOCTYPE html> <html lang="ja"> <meta charset="utf-8" /> <title></title> <body> <ol> <li>a <li>b <li>c </ol> <script type="application/javascript; version=1.8"> var big3 = [ { "name": "google", "url": "http://google.com" }, { "name": "yahoo!", "url": "http://yahoo.com" }, { "name": "bing", "url": "http://bing.com" } ]; var LI = document.querySelectorAll ('body > ol > li'); var func = (function (e) alert (big3[this].name)); Array.forEach (LI, (function (li, i) (li.addEventListener ('click', func.bind (i), false)))); /* for (var i = 0, I = LI.length; i < I; i++) LI[i].addEventListener ('click', func.bind (i), false); */ </script>
- think49
- ベストアンサー率59% (285/482)
jQuery ならこんな感じでしょうか。 http://jsfiddle.net/WVyAr/ バブリングを利用する方がスマートだと思いますが、それ以前にHTMLにもデータを置くなら配列ではなくDOMノードを参照する方がスマートって気がしないでもありません。 <span class="site-name"> のように参照しやすくするとかdata-*属性とかNode#setUserDataとか。 To: #4, 6 さん 横からですが、#4 さんのコードはクロスページリークするんじゃないでしょうか? http://msdn.microsoft.com/ja-jp/library/bb250448%28v=vs.85%29.aspx babu_baboo さんの指摘は「Function#bind を使いましょー」と読みましたが、よくよく調査してみると jQuery には Function#bind の代替がないっぽいです。(jQuery#bind は addEventListener のショートカットのようで) 今ケースでは jQuery.data() が使えそうですが、内部コードが頭を抱えたくなるコードなのでお勧めしがたかったり…。 http://api.jquery.com/jQuery.data/
- reggaepunc
- ベストアンサー率59% (64/108)
jquery使うには、 javascriptが分かる必要がある。 ということですよね。。。 >だまって、bind つかいましょ (笑); ↑も、もしかしてもっと簡潔に書けたりします?(汗
- babu_baboo
- ベストアンサー率51% (268/525)
> 楽して目的を果たす なのに、jQuery のしつもんがおおいのは、なぜ?() jQuery は、さっぱりなものですから・・・ だまって、bind つかいましょ (笑);
- reggaepunc
- ベストアンサー率59% (64/108)
白熱してますね。すばらしい。 えーと私からは、楽して目的を果たす方法をご紹介します。 jquery.jsというありがたいjavascriptライブラリをうまく利用する方法です。 まぁ、こういう書き方もある、ということで、 頭の片隅に置いておいて下さい。 コピペで動きます。 ------------------- <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>test</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script> </head> <body> <script type="text/javascript"> var body = $('body'); var big3 = [ { name:"google", url:"http://google.com" }, { name:"yahoo!", url:"http://yahoo.com" }, { name:"bing", url:"http://bing.com" } ]; for( var i = 0; i < big3.length; i++ ) { var btn = $('<input type="button" value="' + big3[i].name + '">'); btn.click(function( e ) { return function() { alert( big3[e.val].name ); } }({ val : i })); body.append( btn ); } </script> </body> </html> ------------------- ※firefoxでしか確認してないです。
- babu_baboo
- ベストアンサー率51% (268/525)
len 推進派(?)の者です。 やっぱり、それひつようでしょ! (というか、へんすうにつかわれるなまえは、おおもじ派。) 文字列の連結は、配列にして一気に連結する派(?)。 バブリングするイベントは、document で監視する派(?)。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <title>test</title> </head> <body> <div id="hoge"></div> <script type="text/javascript"> var big3 = [ { "name": "google", "url": "http://google.com" }, { "name": "yahoo!", "url": "http://yahoo.com" }, { "name": "bing", "url": "http://bing.com" } ]; var html = ["検索エンジンのビッグ3"]; for (var i = 0, I = big3.length; i < I; i++) { html.push ('名前:' + big3[i].name); html.push ('URL:' + big3[i].url); html.push ('<input type="button" id="btn' + i + '" value="投票" />'); } document.getElementById ("hoge").innerHTML = html.join ('<br />'); function handler (event) { var e = event.target || event.srcElement; var n, c; if ('INPUT' === e.nodeName) if ('button' === e.type) if ('投票' === e.value) if (c = e.id.match (/^btn(\d+)$/)) alert (big3[ Number (c[1]) ].name); } document./*@if (1) attachEvent ('on'+ @else@*/ addEventListener (/*@end@*/ 'click', handler, false); </script> </body> </html> で、ほそくをみたら、Chrome13か~ addEventListenerには、おぶじぇくとをわたすことができるよ。 ついでに、いべんとはんどらーも、おぶじぇくとのなかに、かいちゃえ~! <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <title>test</title> </head> <body> <div id="hoge"></div> <script type="text/javascript"> var Big3 = { 'member' : [ { "name": "google", "url": "http://google.com" }, { "name": "yahoo!", "url": "http://yahoo.com" }, { "name": "bing", "url": "http://bing.com" } ], 'handleEvent' : (function (event) { var e = event.target || event.srcElement; var n, c; if ('INPUT' === e.nodeName) if ('button' === e.type) if ('投票' === e.value) if (c = e.id.match (/^btn(\d+)$/)) alert (this.member[ Number (c[1]) ].name); }), 'demo' : (function (target) { var html = ["検索エンジンのビッグ3"]; var m = this.member; var o; for (var i = 0; o = m[i]; i++) { html.push ('名前:' + o.name); html.push ('URL:' + o.url); html.push ('<input type="button" id="btn' + i + '" value="投票" />'); } target.innerHTML = html.join ('<br />'); target.ownerDocument.addEventListener ('click', this, false); }) }; Big3.demo (document.getElementById ('hoge')); </script> </body> </html> でもね、いいたかったのは、ほかにもある。 big3のられつは、あきらかにりすとこうぞうなのだから <br/>でこうせいされているのが、へん! すくりぷとが、うごかないかんきょうのひとがみても、URLとかなまえとかさいていげんみられるようにしておくべきだよ。 すくりぷとは、そのりすとこうぞうをかいせきしてうごかすべき。 onload も、すくりぷとをさいごにかくことによって、りようしない派、だった! document にいべんとをはりつけておけば、innerHTMLでよみこんだものがあろうがなかろうがかきかえられようが、うごけるし、documentは、すべてよみこみがおわらなくても、そんざいしているだろうし。
- muumiru02
- ベストアンサー率75% (3/4)
>> 下のコードをボタンのすぐ下に置きましたが ... ボタンのすぐ下に置いたというのは、もとのコードはこうだったのでしょうか? html+= "<br />名前:"+big3[i].name+"<br />"; html+= "URL:"+big3[i].url+"<br />"; html+= '<input type="button" id="btn" value="投票" /><br />' document.getElementById("btn").addEventListener('click',function(){alert("あなたがおしたのは"+big3[i].name)},false); }; "cannot call method addEventListener of null"というエラーの意味は、nullオブジェクトに対してaddEventListener()メソッドの呼び出しを行なったけど、nullオブジェクトはそのメソッドを持っていなかったので失敗したということです。 推測で申し訳ないですが、もし上記のようなコードであった場合、document.getElementById('btn')がnullを返すのでこのエラーが発生します。この段階ではまだボタンは生成されていない(DOMツリーに加えられていない)ので対象のボタンを見つけ出そうとしても見つからないからです。 処理の流れとしては、 1.ボタンを生成する 2.ボタンにイベントハンドラを登録する 3.ボタンをDOMツリーに加える という手順をふむ必要があります。2と3の順序は逆でもかまいません。 No1の方が示してくださっているコードを参考にいじってみると動作理解が深まるかと思います。
お礼
ありがとうございます! ブラウザはChrome13です、お二方の回答を元に調べて 進めてみます。
- LOHA
- ベストアンサー率52% (203/388)
それっぽいサンプルを作ってみたので載せておきます。 #インデントは全角スペースになってますので注意 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <title>test</title> <script type="text/javascript"> window.onload = function() { var big3 = [ { "name": "google", "url": "http://google.com" }, { "name": "yahoo!", "url": "http://yahoo.com" }, { "name": "bing", "url": "http://bing.com" } ]; // HTMLの生成 var html = "検索エンジンのビッグ3"; for (var i = 0; i < big3.length; i++) { html += "<br />名前:" + big3[i].name + "<br />"; html += "URL:" + big3[i].url + "<br />"; html += '<input type="button" id="btn' + i + '" value="投票" /><br />'; }; document.getElementById("hoge").innerHTML = html; // Eventの登録用クロージャ var onClick = function(i) { return function() { alert("あなたがおしたのは" + big3[i].name); } } // Eventの登録 for (var i = 0; i < big3.length; i++) { var elem = document.getElementById("btn" + i); if (elem.attachEvent) { elem.attachEvent("onclick", onClick(i)); } else { elem.addEventListener("click", onClick(i), false); } } } </script> </head> <body> <div id="hoge"></div> </body> </html> 以下、何点か補足。 ■len? >for (var i = 0, len = big3.length; i < len; i++) { このlenは特に意味が無い気がします。 普通に for (var i = 0; i < big3.length; i++) { すればよいかと。 ■HTMLのid >html+= '<input type="button" id="btn" value="投票" /><br />' idの値はHTML内で一意でなくてはなりません。classを使う方がスマートな気がしますが、サンプルでは数値を付加することにしてみました。 http://www.tohoho-web.com/html/attr/id.htm ■ブラウザ固有の問題 >cannot call method addEventListener of nullってエラーでできず、 ブラウザとしてIEをお使いではないでしょうか? IE8以下ではイベントを登録するのにattachEventを使用する必要があります。 https://developer.mozilla.org/ja/DOM/element.addEventListener#Internet_Explorer http://journal.mycom.co.jp/news/2010/03/31/032/index.html この手のブラウザ固有の問題はたくさんありますので要注意です。 http://gihyo.jp/dev/serial/01/crossbrowser-javascript/0001 それと、 ><script type=application/javascript> についても、現状<script type="text/javascript">が無難かと思います。 http://ie-style.blogspot.com/2010/03/ie9-javascript-mime.html ■クロージャ 上記ソースではonClick(i)の部分に直接function(){alert("あなたがおしたのは"+big3[i].name)}と入れればいいじゃないかと思われるかもしれませんが、このiはfor文のiの参照です。よって、どのボタンのクリックイベントで呼ばれたときも、このケースではfor文終了時のi=3が参照されます。 それではまずいので、今回はクロージャを利用してみました。 #クロージャとは:http://dqn.sakusakutto.jp/2009/01/javascript.html 関数への引数としてプリミティブ型を渡した場合、値渡しになるので、それを利用しています。 型について:http://www.findxfine.com/index.php?p=228 クロージャの他にもinput要素のプロパティを利用する方法などもあるかと思います。 以上です。 少し難しい内容が入っていますが頑張ってください。
お礼
ありがとうございます! ご紹介いただいたURLを参考にして作ってみます。 クロージャが全く理解できてませんので。。
お礼
回答ありがとうございます!! いつの間にやらいっぱい回答いただいてありがたいです。 初心者という免罪符が役に立たないことは重々承知してますが リスト構造もハブリング?も理解していないのでいただいたサンプル元に 調べてみます。 @とか出てくるととたんにわからなくなる。。