jQuery: определить, нажата ли определенная кнопка в обработчике события 'change' - PullRequest
1 голос
/ 11 октября 2011

Простите, если это просто - я был вдали от компьютеров и JS в течение месяца, так что эта задача кажется мне невозможной, где я знаю, что это не должно быть.

Самый быстрый способМожно подумать, объясняя это, чтобы поместить это в код, используя комментарии, чтобы объяснить, как это работает.В этих комментариях я укажу, какую часть я не могу понять.

У меня есть текстовое поле, которое выглядит как недоступное для редактирования, рядом с ним находится кнопка «Изменить», которая при нажатии превращается в кнопку «Сохранить» и делает текстовое поле выглядящим редактируемым.*

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

Таким образом, он определяет, была ли кнопка сохранения причиной запуска размытия - это то, что я не могу понятьout.

Или, если это совершенно неправильный способ справиться с ситуацией, пожалуйста, дайте мне знать.

(Я должен отметить, что на странице может быть много таких комбинаций полей / кнопок, но пока это ни на что не влияет.)

Ответы [ 2 ]

3 голосов
/ 11 октября 2011

Введение

Это очень интересная (и нетривиальная ИМХО) проблема.Чтобы решить эту проблему, я сначала создал образец страницы, которая имела несколько «групп» текстовых полей и кнопок, которые их включали:

enter image description here

По вашему вопросу, поле ввода отключенопо умолчанию и сделал «редактируемым» нажатием кнопки.

Лучшим решением оказался простой конечный автомат.Конечный автомат помогает понять (большое количество) событий, запускаемых браузером, только просматривая события, которые относятся к текущему состоянию, и игнорируя все остальные.

Реализация

Следующееявляется диаграммой конечного автомата (текст рядом с каждой стрелкой перехода указывает источник и имя события, которое инициирует этот переход):

enter image description here

Решение в действии (Проект JS Fiddle)

Для справки я также включил здесь код 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.Эта функция принимает идентификатор элемента управления вводом и идентификатор соответствующей кнопки, что делает его редактируемым.Затем он создает замыкание с «частным» конечным автоматом.Это означает, что у нас будет один конечный автомат для каждого вызова makeEditable (поскольку разные группы кнопок ввода могут находиться в разных состояниях).

Фактическое «мясо» обработки изменения состояния (что делает текстовое поле редактируемымили отключено) можно найти в setStateNow закрытой функции, когда текущее или новое состояние Locked.

Заключение

Я успешно протестировал решение в Chrome 14, Opera 10.51, IE 9,FireFox 5.0.1, Safari 5.1, Mobile Safari (iPad2).

Одно поведение пользовательского интерфейса, на которое я хотел бы обратить внимание, - это ответ на вопрос Что произойдет, если пользователь нажимает кнопку мыши надкнопка сохранения, но, удерживая кнопку, покидает область кнопки? В этом случае я решил вернуться в редактируемое состояние и снова установить фокус на поле ввода.

Если вы нашли ошибки или подумалиспособ улучшить реализацию, пожалуйста, не стесняйтесь оставлять комментарии к этому ответу.

1 голос
/ 11 октября 2011

Я уверен, что, возможно, есть гораздо лучшее решение, но вот что я придумал:

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

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

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

пример здесь

Я представилнебольшая задержка с setTimeout, поскольку кажется, что при нажатии на кнопку событие blur всегда срабатывает первым до события click кнопки.

...