【學習筆記】JS 在迴圈中設定監聽事件並使用 ajax 設定動態新增的元素的值時出現的問題及其解決方案
阿新 • • 發佈:2022-04-01
問題
for(var i = 1 ; i <= 10 ; i ++) { // 注意迴圈變數 i var newLine = "<tr>"; newLine += "<td><input type='text' id='sampleInput" + i + "'></td>"; newLine += "<td><span id='sampleSpan" + i + "'></td>"; newLine += "</tr>"; // 動態為 newLine 追加 HTML,id 與迴圈變數有關 $("#sampleTable tbody").append(newLine); // 往已存在的 table 中新增新的這一行 $("#sampleInput" + i).on("input", function(){ //這裡設定的監聽物件是沒問題的,能夠實現對於 sampleInput i 的監聽 $.ajax({ type: "get", url: "sampleAction", // data: {}, 假裝這裡有傳別的值 success: function(data){ // data = eval("(" + data + ")"); $("#sampleSpan" + i).html(data); // 這裡想修改 sampleSpan i 的值 } }); }); }
上面這一段 \(JS\) 程式碼,意圖是往 \(sampleTable\) 中插入十行,每行一個文字框 \(sampleInput\{i\}\) 和一個行內元素 \(sampleSpan\{i\}\)
然後對於每行的文字框,只要觸發了 \(input\) 事件就向後臺傳送請求,將獲取到的資料在同一行的行內元素上顯示出來
但這段程式碼的事實卻是,不論修改哪個文字框,行內元素都沒有效果
實際上在 \(ajax\) 的 \(success\) 匿名函式裡看看 \(i\) 的值就清楚了,加一行 \(alert\) 輸出,發現所有 \(i\) 的值都是 \(11\)
這是因為 \(ajax\) 只有執行完請求且獲得資料後才會執行 \(success\)
而在函式內呼叫 \(i\) 這個變數是通過地址去取值的,並沒有把執行 \(ajax\) 時的 \(i\) 的值快取下來,才會出現上面的這種情況
這裡可能有人會說,我直接把 \(ajax\) 的非同步關了就是了 async: false
所以上面的例子裡在外層套了個監聽
監聽事件觸發的時候迴圈肯定是執行完了的,與這個非同步沒有關係
解決
解決方法,把需要的值通過 \(ajax\) 傳給後端,讓後端重新傳回來,問題解決(簡單粗暴)
因為傳入值時還沒有開始非同步執行,引用的 \(i\)
for(var i = 1 ; i <= 10 ; i ++) {
var newLine = "<tr>";
newLine += "<td><input type='text' id='sampleInput" + i + "'></td>";
newLine += "<td><span id='sampleSpan" + i + "'></td>";
newLine += "</tr>";
$("#sampleTable tbody").append(newLine);
$("#sampleInput" + i).on("input", function(){
$.ajax({
type: "get",
url: "sampleAction",
data: {id: i}, // 把需要的值 i 傳給後端
success: function(data){
data = eval("(" + data + ")");
var i = data.id; // 讓 action 再把它返回來就是了
$("#sampleSpan" + i).html(data.data);
}
});
});
}
後記:
挺奇妙的,在 debug 的時候竟然沒有遇到“無法找到動態新增的元素”的問題
本來我是往這個方向想的,於是就捨棄了通過 id 來查詢元素,換了其他麻煩的方法(相對位置檢索大法)
然後重新回來看這個問題,越看越奇怪,於是輸出了一下迴圈變數,直接豁然開朗……