2010-12-19 75 views
2

爲了把事情放在上下文中,我通過Ajax加載項目列表,爲每個項目創建一個包含主要信息的div,並希望在點擊頁面時顯示詳細信息。所以我有我的onSuccess代碼:Event.observe在一個循環和變量

items = transport.responseText.evalJSON(); // my list of objects that contains all the details I'll need for that page 
for (var itemID in items) 
{ 
    newDiv = ... // Creating my div with main infos 
    $('myDiv').appendChild(newDiv); 

    // More code to make everything look pretty and that works fine 

    Event.observe(newDiv, 'click', function() { loadItem(itemID); }); 
} 

loadItem是我的功能,將顯示所有項目的詳細信息。而我的問題是itemID在創建觀察事件時不會被其值取代,所以它總是返回所有項目的相同ID。

任何想法如何解決這個問題?我在原型doc上檢查了綁定,這似乎是針對這些情況製作的,但可能沒有得到它,因爲它不適用於我。

回答

5

對於最小衝擊的修復,這個替換您的Event.observe行:

Event.observe(newDiv, 'click', loadItem.curry(itemID)); 

說明:

在你的原代碼,事件處理程序要創建功能關閉了(有對itemID變量的持久引用,所以當事件處理程序爲時,將使用該變量的值爲,而不是在將其分配給事件時。對於所有處理函數,該值將是itemID在循環  —中具有的最後一個值。 More about closures here.

具有最小衝擊修改後的代碼中,我們使用原型的curry功能,這將創建一個功能你,調用它時,會調用底層函數與你給curry的參數。 (這個名字是from mathematics;哈斯克爾庫裏想出的技術,雖然有爭論,他不是第一個這樣做的。)我們可以做自己同樣的事情:

items = transport.responseText.evalJSON(); // my list of objects that contains all the details I'll need for that page 
for (var itemID in items) 
{ 
    newDiv = ... // Creating my div with main infos 
    $('myDiv').appendChild(newDiv); 

    // More code to make everything look pretty and that works fine 

    Event.observe(newDiv, 'click', prepLoadItem(itemID)); 
} 

function prepLoadItem(id) { 
    return function() { 
     loadItem(id); 
    }; 
} 

...但因爲原型有一個通用的功能,我們不需要。

題外話:是items數組?如果不是,請忽略此題外評論。如果是這樣,不要使用for..in來循環它,或者至少,除非你採取一些預防措施,上面的代碼不能正確地做到這一點。 Details here,但是for..in而不是用於循環數組的索引;它用於循環對象的屬性。數組對象可能具有除數組索引之外的其他屬性(實際上,如果您使用的是原型,他們可以。)

+0

啊謝謝它的作品,現在我今天學到了一個新的JS技巧! – Charles 2010-12-19 10:23:31

+0

謝謝你在答案中的出色解釋。 +1 – 2014-11-17 21:15:48