2011-10-11 39 views
1

原諒我,如果這很簡單 - 我已經遠離電腦和JS一個月了,所以這個任務對我來說似乎是不可能的,在那裏我知道它不應該'不要。jQuery:檢測'change'事件處理程序中是否點擊某個按鈕

我能想到的最快捷的解釋就是把它放在代碼中,用註釋來解釋它是如何工作的。我會在這些評論中指出哪些是我無法弄清楚的部分。

我有一個看起來不可編輯的文本字段,旁邊有一個「編輯」按鈕,點擊後變爲「保存」按鈕,並使文本字段看起來可編輯。

$(".edit_btn").click(function() { 
    // make the associated text field look editable, and change this 'edit' 
    // button into a 'save' button. Then place focus on the text in 
    // in the field. 
}); 

$(".save_btn").click(function() { 
    // if (value in associated text field has changed from when page loaded) 
    // submit the form and save this new text 
    // else 
    // revert to non-editable mode (hide this 'save' button, 
    // and show 'edit' button) 
}); 

所有的工作正常。但是,如果用戶離開可編輯文本字段,我希望能夠檢測他們是否已離開字段以單擊「保存」按鈕,或者只是單擊頁面上的其他任何位置。因此,在該字段的「模糊」事件處理程序中,我需要知道是否點擊了「保存」按鈕。對於我的生活,我無法弄清楚如何做到這一點:

$('input[name^="tgfld_"]').blur(function() { 
    // if (save button has been clicked) <- this is the problem 
    // don't do anything since the save function will handle this 
    // else if (value in the field hasn't changed) 
    // revert everything back to non-editable mode 
    // else if (value in the field HAS changed) 
    // do a window.confirm and prompt the user to click the 'save' 
    // button to save their changes 
}); 

所以它的檢測,如果保存按鈕是爲「模糊」被觸發的原因 - 這就是我想不通。或者,如果這完全是處理這種情況的錯誤方式,請讓我知道。

(我應該指出的是,可能有許多頁面上這些字段/按鈕組合,但至今未影響到任何東西。)

+0

這有幫助嗎? http://stackoverflow.com/q/6411271/497356 –

回答

3

介紹

這是一個非常有趣的(和不平凡的恕我直言)問題。爲了解決這個問題我先創建了,使他們的文本輸入框和按鈕多個「組」的樣本頁:

enter image description here

根據您的問題,輸入框默認情況下禁用並取得「編輯「通過點擊一個按鈕。

最好的解決方案原來是一個簡單的狀態機。狀態機通過查看適用於當前狀態的事件並忽略所有其他事件來幫助理解瀏覽器觸發的(大量)事件。

實施

下面是狀態機的示圖(文本旁邊的每個過渡箭頭指定觸發轉換的事件的源和名稱):

enter image description here

Solution in action (JS Fiddle project)

僅供參考我還在這裏包括JavaScript代碼:

function makeEditable(inputId, btnId) { 
    var state = "Locked", timeout = null, $input = $("#" + inputId), $btn = $("#" + btnId); 

    function setStateNow(precondition, newState, e) { 
     if (!precondition || state === precondition) { 
      if (window.console) { window.console.log("State change: " + state + " => " + newState + " (from " + e.target.id + "." + e.type + ")"); } 
      if (newState === "Locked") { // changing from any state to Locked 
       $input.prop("disabled", true); 
       $btn.val("Edit"); 
      } else if (state === "Locked") { // changing from Locked to any other state 
       $input.prop("disabled", false).focus(); 
       $btn.val("Save"); 
      } 
      if (newState === "LockPending") { // changing from any state to LockPending 
       timeout = setTimeout(
        function() { setStateNow("LockPending", "Locked", { target: { id: e.target.id }, type: "setTimeout" }); }, 
        20); 
      } else if (state === "LockPending") { // changing from LockPending to any other state 
       if (timeout) { 
        clearTimeout(timeout); 
        timeout = null; 
       } 
      } 
      if (newState === "Editable" && state === "LockPendingMouse") { 
       $input.focus(); 
      } 

      state = newState; 
      return true; 
     } 
     return false; 
    } 


    function setState(e) { 
     var r; 
     if (e.data.rules) { 
      for (i in e.data.rules) { 
       r = e.data.rules[i]; 
       if (setStateNow(r.precondition, r.newState, e)) { 
        return; 
       } 
      } 
     } else { 
      setStateNow(e.data.precondition, e.data.newState, e); 
     } 
    } 


    $input 
     .focus ({ precondition: "LockPending", newState: "Editable" }, setState) 
     .blur({ precondition: "Editable", newState: "LockPending" }, setState); 

    $btn 
     .click({ rules: [{ precondition: "Locked", newState: "Editable" }, { precondition: "LockPendingMouse", newState: "Locked" }, { precondition: "Editable", newState: "Locked" }] }, setState) 
     .mousedown({ precondition: "Editable", newState: "LockPendingMouse" }, setState) 
     .mouseleave({ precondition: "LockPendingMouse", newState: "Editable" }, setState) 
     .focus ({ precondition: "LockPending", newState: "Editable" }, setState) 
     .blur({ precondition: "Editable", newState: "LockPending" }, setState); 
} 

該代碼定義了一個函數,makeEditable。該功能接受輸入控件的ID和使其可編輯的相應按鈕的ID。然後它創建一個「私人」狀態機關閉。這意味着我們每調用一個makeEditable就會有一個狀態機(因爲不同的輸入按鈕組可能處於不同的狀態)。

當前狀態或新狀態爲Locked時,可以在setStateNow私鑰函數中找到狀態更改處理(使文本框可編輯或禁用)的實際「肉」。

結論

我成功地測試了溶液中鉻14,歌劇10.51,IE 9,火狐5.0.1時,Safari 5.1,移動Safari(iPad2的)。

我想指出的一個用戶界面行爲是對問題的回答如果用戶在保存按鈕上按下鼠標按鈕,但仍然按住按鈕留下按鈕區域,會發生什麼情況?在這種情況下,我決定返回到可編輯狀態並再次將焦點設置到輸入字段。

如果您發現錯誤或想辦法改進實施,請隨時留下評論意見。

1

我敢肯定,有可能是一個更好的解決方案,但這裏是我想出了:

$(document).ready(function() { 
    saved = false; 

    $('#button').click(function() { 
     saved = true; 
    }); 

    $('#input').blur(function() { 
     var t = setTimeout("if(!saved) {alert('not saved!');}",400); 
    }); 
}); 

example here

我引入了setTimeout輕微的延遲,因爲它出現在按鈕上點擊時,該blur事件總是首先觸發日之前e按鈕的click事件。

+0

我曾經想過這是一個備份解決方案,如果更優雅或明顯不明顯的東西沒有被拍在我的臉上。不過感謝提醒我,因爲我已經開始認爲我的備份選項是檢測字段模糊處理程序中鼠標的X,Y座標,並查看它們是否落在關聯的按鈕上。這只是複雜的方法。 –

+0

實際上,您可以使用此方法並將其應用於具有某個類的所有元素,而不是使用id。每個輸入都可以使用jQuery .data()方法存儲自己的「保存」變量。 –

相關問題