webentwicklung-frage-antwort-db.com.de

Ändern Sie den asynchronen jQuery-Dialog, um synchron zu sein.

Derzeit arbeite ich daran, "alert"/"confirm" durch den Jquery-Dialog zu ersetzen.

Aber die meisten älteren Codes sind asynchron geschrieben, was die Änderung schwierig macht. Gibt es eine Möglichkeit, den Jquery-Dialog synchron zu machen? (Keine Loop- oder Callback-Funktion verwenden)

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

In diesem Beispiel werden der Alarm und andere Codes nach Wahl des Benutzers ausgeführt.

Wenn wir jquery dialog verwenden Var result = $ dialog.open () Die Warnung wird weiterhin asynchron ausgeführt.

Derzeit besteht meine Lösung darin, die Rückruffunktion in der Funktion OK | Abbrechen .. zu verwenden. Zum Beispiel:

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

Diese Methode funktioniert, aber es ist schwierig, alle synchronen Codes asynchron zu machen, was viele Änderungen erfordert (siehe folgendes Beispiel). Also suche ich nach dem synchronen jQuery-Dialog, ist das möglich?

Zum Beispiel: (Die echten Codes sind viel komplizierter als das folgende Beispiel)

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

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

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

Ein anderes Beispiel:

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

... hier löst das Kreditorobjekt ein Ereignis aus, das bei Bestätigung durch den Benutzer abgesagt werden muss. Das Ereignis kann nur abgebrochen werden, wenn der Ereignishandler false - synchron zurückgibt.

36
user881284

Die kurze Antwort lautet nein, Sie können Ihren Code nicht synchron halten. Hier ist der Grund:

  • Damit dies synchron ist, müsste das aktuell ausgeführte Skript auf die Eingabe durch den Benutzer warten und dann fortfahren.
  • Während ein Skript gerade ausgeführt wird, kann der Benutzer nicht mit der Benutzeroberfläche interagieren. Tatsächlich wird die Benutzeroberfläche erst aktualisiert, nachdem das Skript ausgeführt wurde.
  • Wenn das Skript nicht fortgesetzt werden kann, bis der Benutzer Eingaben getätigt hat, und der Benutzer keine Eingaben vornehmen kann, bis das Skript abgeschlossen ist, ist der nächstliegende Browser ein blockierter Browser. 

Um dieses Verhalten zu veranschaulichen, debuggen Sie Ihren Code, und legen Sie einen Haltepunkt in der Zeile fest, der auf eine Zeile folgt, die die Benutzeroberfläche ändert:

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

Beachten Sie, dass Ihr Seitenhintergrund noch nicht rot ist. Sie wird nicht rot angezeigt, wenn Sie die Ausführung fortsetzen und die Ausführung des Skripts abgeschlossen ist. Sie können auch keine Links auf Ihrer Seite anklicken, wenn die Skriptausführung mit Ihrem Debugger angehalten wurde.

Es gibt eine Ausnahme von dieser Regel für alert() und confirm(). Dies sind Browsersteuerelemente, die anders behandelt werden als die Elemente der Benutzeroberfläche der Webseite.

Die gute Nachricht ist, dass es wirklich nicht schwer sein sollte, Ihren Code zu konvertieren. Vermutlich sieht Ihr Code derzeit so aus:

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

Ihre asynchrone Version könnte eine Funktion ifConfirm(text, yesFn, noFn, finallyFn) erstellen, und Ihr Code würde sehr ähnlich aussehen:

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

Edit: Als Antwort auf das zusätzliche Beispiel, das Sie zu Ihrer Frage hinzugefügt haben, muss der Code leider umgestaltet werden. Es ist einfach nicht möglich, synchrone benutzerdefinierte Bestätigungsdialogfelder zu haben. Um ein benutzerdefiniertes Bestätigungsdialogfeld in einem Szenario zu verwenden, in dem ein Ereignis entweder fortgesetzt oder abgebrochen werden muss, müssen Sie das Ereignis immer abbrechen und das Ereignis im Callback yesFn nachahmen.

Zum Beispiel einen Link:

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

Oder ein Formular:

$("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

Ich bin mir nicht ganz sicher, was die Motivation für die Verwendung von Rückrufen ist. Daher ist es schwer zu beurteilen, welche Lösung Ihre Anforderungen erfüllen könnte. Eine andere Möglichkeit, die Ausführung zu verzögern, ist das "verzögerte" Objekt von jQuery. 

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

Sie können eine Funktion einrichten, die das Jquery-Dialogfeld öffnet, und Code hinzufügen, der auf das Schließen des Dialogfelds "wartet". Dies funktioniert auf ähnliche Weise wie ein Rückruf in dem von Ihnen angelegten Fall, aber hier ist ein Beispiel:

    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);

            });
        });

    });

Hier arbeitet es in jsFiddle: http://jsfiddle.net/FJMuJ/

8
Ben L

Nein, Sie können in Javascript keine Synchronisierung durchführen (Warnung verstößt tatsächlich gegen die Regeln). Javascript wird im Kern mit "single-thread, async" erstellt.

Was Sie jedoch tun können, ist die Deaktivierung der Funktionalität der darunter liegenden Seite (Leuchtkasten), sodass kein Ereignis von der Seite ausgelöst wird, bis Sie die Dialogaktion nicht ausführen, entweder OK oder Abbrechen. Dies ist jedoch nicht hilfreich, um den Synchronisierungscode zum Laufen zu bringen. Du musst umschreiben.

3
user1046334

Hier sind einige Ideen - Sie möchten Ihr asynchrones Ereignis tatsächlich blockieren, damit es wie synchronisiert aussieht. Hier sind einige Links:

Warteschlangen für asynchrone Anrufe

Mobl

Narrative JavaScript

Hoffe das hilft dir weiter !!

1
Leon

Um die spezifischere Frage von David Whiteman zu beantworten, implementiere ich ein "verzögertes" Postback für ein LinkButton-Click-Ereignis. Grundsätzlich verhindere ich nur das Standardverhalten und feuere das Postback manuell ab, wenn Benutzerfeedback verfügbar ist.

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