2011-01-06 14 views
0

私の関数は、ドキュメント内のすべてのフォームを繰り返し、onclick関数をフォームの各 'calculate'要素にバインドすることになっています。問題は、いずれかのクリックイベントで実行される関数が、ループ内の最後のiのコンテキストで実行されることです。ここで フォームの反復関数が正しく動作しない

は、私が使用しているJavaScriptのである:

window.onload = function(){ 
    calculateSavings(); 
} 

function calculateSavings(){ 
    for (i = 0; i < document.forms.length; i++) { 
     var e = document.forms[i]; 
     e.calculate.onclick = function() { 
      var hours = e.hours.value; 
      var rate = e.rate.value; 
      alert(hours * rate); 
     } 
    } 
} 

をそしてここでそれが接続されているHTMLである:私はこれは本当に基本的な質問であると確信しているが、

<!doctype html> 
<html> 
<body> 
<form> 
    <label for="hours">Hours: </label><input type="text" id="hours" name="hours"> 
    <label for="rate">Rate: </label><input type="text" id="rate" name="rate"> 
    <input type="button" name="calculate" value="Calculate"> 
    <div id="savings"></div> 
</form> 
<form> 
    <label for="hours">Hours: </label><input type="text" id="hours" name="hours"> 
    <label for="rate">Rate: </label><input type="text" id="rate" name="rate"> 
    <input type="button" name="calculate" value="Calculate"> 
    <div id="savings"></div> 
</form> 
</body> 
</html> 

解決策は、この時点で私を完全に逃しています。 http://jsfiddle.net/KcNWy/

+0

あなたはjQueryを使用していますか? DOM操作を楽にするでしょう。 –

+0

すべてのフォームのすべての異なる要素は、同じID /フォームを持っていますか? –

+0

@meder正直言って、私はむしろjQueryを避けるでしょう。 innerHTMLステートメントを追加するだけでなく、ここで見ている小さなJavaScriptは、私がページ上で使用するすべてのものです。 – Moses

答えて

4

クローズループの問題があります。参照してください、私は知らない、thisまたは約100万人の他の人が同じ問題によって引き起こされる質問。

ieがループ中に同じ変数です:ループは単にieを変更し、それはあなたに新しいeを与えるものではありません。したがって、function() { ... }が起動すると、ループが反復処理を終了してからずっと後に、eには最後に一致した入力値が残ります。

(また、あなたがvar iを宣言していないので、iはそれよりも悪い、それは偶然のグローバルです。)

その周りに典型的な方法は、値のコピーを保持するために、別の関数スコープを追加することです作成時に、閉鎖中:

e.elements.calculate.onclick = function(e) { 
    var hours = this.elements.hours.value; 
    var rate = this.elements.rate.value; 
    alert(hours * rate); 
}.bind(e); 

e.elements.calculate.onclick = function(e) { 
    return function() { 
     var hours = e.elements.hours.value; 
     var rate = e.elements.rate.value; 
     alert(hours * rate); 
    } 
}(e); 

あなたはFunction#bind方法ではECMAScript第5版では、よりきれいにそれを行うことができます

がありますが、これはまだこの方法をサポートしていない既存のブラウザに対するこのメソッドのためのadding supportを意味します。あるいはループ機構自体で閉鎖を入れ

は、問題を回避:

forEach(document.forms, function(form) { 
    form.elements.calculate.onclick = function() { 
     var hours = form.elements.hours.value; 
     var rate = form.elements.rate.value; 
     alert(hours * rate); 
    } 
}); 

function forEach(list, callback) { 
    for (var i= 0, n= list.length; i<n; i++) 
     callback(list[i]); 
} 

あるいは代替的に、ちょうど同じ機能を毎回使用して、クリックされた要素からフォーム参照をつかむ:

for (var i= document.forms.length; i-->0;) 
    document.forms[i].elements.calculate.onclick= calculate_click; 

function calculate_click() { 
    var hours = this.form.elements.hours.value; 
    var rate = this.form.elements.rate.value; 
    alert(hours * rate); 
} 
+0

私はJS:The Definitive Guideを読んだときにクロージャーを理解したことはありませんでしたが、私の問題を解決して、クロージャーの仕組みがほんの数分でわかるようになりました!また、グローバルiをつかまえていただきありがとうございます:) – Moses

0

は、あなたが「この」ではなく「e」を使用してのonclickの関数内で参照するために使用することができます:ここで

は、私が経験してる問題のデモですか?

関連する問題