it-swarm.com.ru

Изменить асинхронный диалог JQuery на синхронный?

В настоящее время я работаю над заменой «alert»/«verify» на диалог jquery.

Но большинство устаревших кодов написано каким-то асинхронным способом, что затрудняет изменение. Есть ли способ заставить диалог jquery работать синхронно? (не используйте цикл или функцию обратного вызова)

   For example:
   function run()
   { 
      var result = confirm("yes or no");
      alert( result );
      \\more codes here
   }

В этом примере предупреждение и другие коды будут выполняться по выбору пользователя.

Если мы используем jquery dialog Var result = $ dialog.open () Он будет продолжать выполнять предупреждение, которое является асинхронным.

В настоящее время мое решение заключается в использовании функции обратного вызова в функции OK | Cancel . Например:

    OK: function ()
   {
       $dialog.close();
       alert("yes");
       //more codes here
    }

Этот метод работает, но трудно заставить все синхронные коды стать асинхронными, что требует больших изменений (см. Следующий пример). Итак, я ищу синхронный диалог JQuery, это возможно?

Например: (Реальные коды намного сложнее, чем в следующем примере)

     function f1()
    {
          if ( confirm("hello") )    f2();
          alert("no");
    } 

    function f2()
    {
          if( confirm("world") )    f3();
          alert("no");
    }

    function f3()
    {
          return confirm("!") ;
    }

Другой пример:

vendorObject.on('some-event', function() {
    if(confirm("Do you really want to do that?")) {
        return true;
    }
    else {
        return false; // cancel the event
    }
});

... здесь объект vendor запускает событие, которое должно быть отменено, если пользователь подтверждает. Событие может быть отменено, только если обработчик события возвращает false - синхронно.

36
user881284

Короткий ответ - нет, вы не сможете сохранить свой код синхронным. Вот почему:

  • Для того чтобы это было синхронно, исполняемый в данный момент сценарий должен будет дождаться, пока пользователь предоставит ввод, а затем продолжить.
  • Несмотря на то, что в настоящее время выполняется сценарий, пользователь не может взаимодействовать с пользовательским интерфейсом. На самом деле, пользовательский интерфейс даже не обновляется, пока не завершится выполнение скрипта.
  • Если сценарий не может быть продолжен до тех пор, пока пользователь не предоставит ввод, и пользователь не сможет обеспечить ввод до тех пор, пока сценарий не будет завершен, самый близкий из них - зависший браузер. 

Чтобы проиллюстрировать это поведение, отладьте свой код и установите точку останова на строке, следующей за строкой, которая изменяет пользовательский интерфейс:

$("body").css("backgroundColor", "red");
var x = 1;  // break on this line

Обратите внимание, что фон вашей страницы еще не красный. Он не изменится на красный, пока вы не возобновите выполнение и сценарий не завершит выполнение. Вы также не можете нажимать ссылки на своей странице, когда выполнение сценария приостановлено с помощью отладчика.

Из этого правила есть исключение для alert() и confirm(). Это элементы управления браузером, и они обрабатываются иначе, чем реальные элементы пользовательского интерфейса веб-страницы.

Хорошая новость это то, что на самом деле не должно быть очень сложно конвертировать ваш код. Предположительно, ваш код в настоящее время выглядит примерно так:

if (confirm("continue?")) {
    // several lines of code if yes
}
else {
    // several lines of code if no
}
// several lines of code finally 

Ваша асинхронная версия может создать функцию ifConfirm(text, yesFn, noFn, finallyFn), и ваш код будет выглядеть примерно так же:

ifConfirm("continue?", function () {
    // several lines of code if yes
},
function () {
    // several lines of code if no
},
function () {
    // several lines of code finally 
});

Правка: В ответ на дополнительный пример, который вы добавили в свой вопрос, к сожалению, этот код придется реорганизовать. Просто невозможно иметь синхронные пользовательские диалоги подтверждения. Чтобы использовать настраиваемое диалоговое окно подтверждения в сценарии, в котором событие необходимо продолжить или отменить, вам просто нужно всегда отменять событие и имитировать событие в обратном вызове yesFn.

Например, ссылка:

$("a[href]").click(function (e) {
    e.preventDefault();
    var link = this.href;
    ifConfirm("Are you sure you want to leave this awesome page?", function () {
        location.href = link;
    });
});

Или форма:

$("form").submit(function (e) {
    e.preventDefault();
    var form = this;
    ifConfirm("Are you sure you're ready to submit this form?", function () {
        form.submit();
    });
});
34
gilly3

Я не совсем уверен, что мотивирует не использовать обратные вызовы, поэтому трудно судить, какое решение может удовлетворить ваши требования, но другой способ отложить выполнение - через «отложенный» объект jQuery. 

http://api.jquery.com/category/deferred-object/

Вы можете настроить функцию, которая открывает диалог jquery и добавить код, который «ждет» закрытия диалога. Это заканчивается тем, что работает довольно схожим образом с обратным вызовом в случае, который вы выложили, но вот пример:

    function confirm () {
        var defer = $.Deferred(); 
        $('<div>Do you want to continue?</div>').dialog({
                autoOpen: true,
                close: function () { 
                    $(this).dialog('destroy');
                },
                position: ['left', 'top'],
                title: 'Continue?',
                buttons: {
                    "Yes": function() {
                        defer.resolve("yes"); //on Yes click, end deferred state successfully with yes value
                        $( this ).dialog( "close" );
                    },
                    "No": function() {
                        defer.resolve("no"); //on No click end deferred successfully with no value
                        $( this ).dialog( "close" );
                    }
                }
            });
        return defer.promise(); //important to return the deferred promise
    }

    $(document).ready(function () {
        $('#prod_btn').click(function () {
            confirm().then(function (answer) {//then will run if Yes or No is clicked
                alert('run all my code on '  + answer);

            });
        });

    });

Здесь это работает в jsFiddle: http://jsfiddle.net/FJMuJ/

8
Ben L

Нет, вы не можете ничего синхронизировать в Javascript (на самом деле предупреждение нарушает правила). Javascript построен с «однопоточным, асинхронным» в ядре.

Однако вы можете отключить функциональность базовой страницы (в виде лайтбокса), чтобы никакое событие не вызывалось со страницы до тех пор, пока вы не предпримете действие диалога, будь то ОК или Отмена. Думаю, это не поможет вам заставить ваш код синхронизации работать. Вы должны переписать.

3
user1046334

Вот несколько идей - вам нужно заблокировать асинхронное событие, чтобы оно выглядело как синхронизированное. Вот несколько ссылок:

Очередь асинхронных вызовов

Мобл

Повествовательный JavaScript

Надеюсь, это поможет вам дальше!

1
Leon

Чтобы ответить на более конкретный вопрос Дэвида Уайтмена, вот как я реализую «отложенный» постбэк для события ClickButton Click. По сути, я просто запрещаю поведение по умолчанию и запускаю обратную передачу вручную, когда доступна обратная связь с пользователем.

function MyClientClickHandler(event, confirmationMessage, yesText, noText) {
    // My LinkButtons are created dynamically, so I compute the caller's ID
    var elementName = event.srcElement.id.replace(/_/g, '$');
    // I don't want the event to be fired immediately because I want to add a parameter based on user's input
    event.preventDefault();
    $('<p>' + confirmationMessage + '</p>').dialog({
        buttons: [
        {
            text: yesText,
            click: function () {
                $(this).dialog("close");
                // Now I'm ready to fire the postback
                __doPostBack(elementName, 'Y');
            }
        },
        {
            text: noText,
            click: function () {
                $(this).dialog("close");
                // In my case, I need a postback when the user presses "no" as well
                __doPostBack(elementName, 'N');
            }
        }
        ]
    });
}
0
Sue Maurizio