2011-10-11 5 views
1

간단하다면 용서해주십시오. - 컴퓨터와 JS에서 한 달 동안 떨어져 있었으므로이 작업은 불가능한 것처럼 보입니다. 그러지 마라.jQuery : '변경'이벤트 핸들러 내에서 특정 버튼을 클릭하면 감지

내가 설명 할 수있는 가장 빠른 방법은 코드를 사용하여 주석을 사용하여 작동 원리를 설명하는 것입니다. 나는이 설명에서 내가 알 수없는 부분을 지적 할 것이다.

나는 편집 할 수 없도록 스타일이 지정된 텍스트 필드가 있으며, 옆에 '편집'버튼이 있습니다.이 버튼을 클릭하면 '저장'버튼으로 바뀌고 텍스트 필드는 편집 가능한 모양이됩니다.

$(".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) 
}); 

모두 제대로 작동합니다. 그러나 사용자가 편집 가능한 텍스트 필드를 떠난 경우 필드를 떠나 '저장'버튼을 클릭했는지 또는 페이지의 다른 곳을 클릭했는지 여부를 감지 할 수 있기를 원합니다. 그래서 필드의 'blur'이벤트 처리기 내에서 '저장'버튼을 클릭했는지 알아야합니다. 내 인생 내가 그것을 어떻게 알아낼 수 없습니다 :

$('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 
}); 

을 저장 버튼이 트리거되는 '흐림'에 대한 이유가 있다면 그래서이 감지 것 - 그게 내가 알아낼 수 없습니다거야.

또는 이것이 완전히 잘못된 상황 처리 방법이라면 알려 주시기 바랍니다.

(I 페이지에서 이러한 필드/버튼 조합의 많은,하지만 지금까지 그 영향을 미치는되지 않은 것도있을 수 있음을 지적한다.)

+0

전혀 도움이 되나요? http://stackoverflow.com/q/6411271/497356 –

답변

3

소개

이것은 매우 흥미로운 (및 비 사소한 IMHO) 문제입니다. 그것을 해결하기 위해 내가 먼저 있도록 텍스트 입력 상자와 버튼의 여러 "그룹"한 샘플 페이지 생성 :

질문으로 당 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, 사파리 5.1, 모바일 사파리 (아이 패드)에 솔루션을 테스트했다.

내가 지적하고자하는 UI 동작 중 하나는 질문에 대한 대답입니다. 사용자가 저장 버튼 위로 마우스 버튼을 누르고 있지만 버튼을 계속 누르고 있으면 어떻게됩니까?이 경우 편집 가능한 상태로 돌아가서 입력 필드로 다시 초점을 설정하기로 결정했습니다.

버그를 발견하거나 구현 방법을 개선하려는 생각이 있으시면 언제든지이 답변에 대한 의견을 남기십시오.

1

을 나는 확신 훨씬 더 나은 솔루션은 아마이 이 버튼을 클릭하면, blur 이벤트가 항상 일하기 전에 먼저 발사 것으로 보인다 때문에 나는 setTimeout에 약간의 지연을 도입

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

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

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

example here

:하지만 여기 내가 생각 해낸 것입니다 e 버튼의 click 이벤트.

+0

나는 백업 솔루션으로 이것에 대해 생각해 보았습니다. 더 우아하고 무언가가 명백한 것이 내 얼굴에 부딪치지 않았다면. 내 백업 옵션은 필드 흐림 처리기에서 마우스의 X, Y 좌표를 감지하고 관련 버튼에 있는지 확인하기위한 것이었기 때문에 저를 상기시켜 주셔서 감사드립니다. 그것은 단지 복잡한 방법입니다. –

+0

실제로이 메서드를 사용하여 id를 사용하는 대신 특정 클래스가있는 모든 요소에이 메서드를 적용 할 수 있습니다. 각 입력은 jQuery .data() 메소드를 사용하여 '저장된'변수를 저장할 수 있습니다. –