22

I'm trying to use the jQuery alerts dialog library from http://abeautifulsite.net/notebook/87 instead of the default alerts (which look pretty awful in my opinion). This seems to be a great library, but there is not an example of how to use the jConfirm library.

I need to do something like this:

function confirm() {
        var result = false;
        var response = false;
        jConfirm('are you sure?', 'Confirmation Dialog',
          function(r) {
            result = r;
            response = true;
            return r;
        });
        if (response == true) {
            alert(result);
            return result;
        }
        else {
            //wait for response
            alert('hi');
        }
    }

and my call from my .net button:

I've posted a comment on the plugin's website (just this morning) and did Google searches for javascript and waiting for a callback to complete with no results.

Any ideas on how to use the callback correctly to get the result, before the rest of the javascript executes?

Thanks.

AlignedDev
  • 8,102
  • 9
  • 56
  • 91
  • Update: check out the authors site. He left a comment that it wasn't really intended to have it function the way I wanted it to. The answers to this post prove that as well. Thanks everyone!! – AlignedDev Feb 06 '09 at 15:58
  • There is a plugin there: http://stackoverflow.com/questions/6457750/form-confirm-before-submit/12357337#12357337 –  Sep 11 '12 at 12:16

9 Answers9

19

You've just hit a big limitation in JavaScript. Once your code enters the asynchronous world, there is no way to get back to a classic procedural execution flow.

In your example, the solution would be to make a loop waiting for the response to be filled. The problem is that JavaScript does not provide any instruction that will allow you to loop indefinitely without taking 100% of the processing power. So you will end up blocking the browser, sometimes to the point where your user won't be able to answer the actual question.

The only solution here is to stick to the asynchronous model and keep it. My advice is that you should add a callback to any function that must do some asynchronous work, so that the caller can execute something at the end of your function.

function confirm(fnCallback) 
{
    jConfirm('are you sure?', 'Confirmation Dialog', function(r) 
    {
        // Do something with r 

        fnCallback && fnCallback(r); // call the callback if provided
    });
}

// in the caller

alert('begin');

confirm(function(r)
{
    alert(r);

    alert('end');
})
Vincent Robert
  • 35,564
  • 14
  • 82
  • 119
  • It's not a limitation in javascript. It's the way html web-pages work. Nothing to do with javascript. – dkretz Jan 16 '09 at 07:06
  • 13
    It is a limitation of the language not to be able to have a way to yield to the browser while staying in the same context. If this was possible, we could write "doAjax(); while( !ajaxDone() ){ Sleep(); }". But this is impossible in Javascript because there is no Sleep or similar function... – Vincent Robert Jan 21 '09 at 17:51
  • 2
    GREAT conceptualization of the asynchronous and procedural models. Often many have code that is a mixture of both and don't realize how to solve a problem that requires only using one, as was the case with me before I read this answer ;) – Kevin Jul 14 '11 at 20:37
  • @dkretz: Of course it's a limitation of Javascript (as described; different now in 2019). Yes, web pages work asynchronously, for the convenience of the user. But event loops aren't the only way to do asynchronous programming. – user1071847 May 15 '19 at 12:14
16
jConfirm('are you sure?', 'Confirmation Dialog',
    function(r) {
        result = r;
        response = true;
        return r;
    }
);
if (response == true) {

This betrays a misunderstanding of the sequence of events that occurs using asynchronous code. Just because you've written it inline doesn't mean it's going to execute strictly top-to-bottom.

  1. jConfirm is called, receiving a function as one of its parameters, which it remembers.
  2. jConfirm displays its UI on the page and returns immediately.
  3. The 'if (response==true)' line executes. Really this should just read 'if (response)', the boolean comparison is superfluous. But in any case response is of course false. Your function gives up and exits, giving control back to the browser.
  4. The user clicks jConfirm's UI.
  5. jConfirm only now jumps into action and calls back the function you gave it and it remembered earlier.
  6. Your nested function sets response true, far too late for the 'if (response==true)' condition to do anything with it.

You have written "//wait for response" as an alternative, but there is no JavaScript code you can write that will actually do that. Your function must return to give control back to the browser, before the browser can fire the click events on the jConfirm UI that make processing proceed.

Ways to make asynchronous code work in a synchronous context (and vice versa) exist - in particular threads and coroutines (and their limited relation generators). But JavaScript has none of these features, so you must write your code to fit the synchronous-or-asynchronous model your library is using.

bobince
  • 528,062
  • 107
  • 651
  • 834
8

Since the callback is asynchronous (at least, in the sense that it's waiting on the user to do something), it might be easier to handle what you need to inside the callback:

function confirm() {
    jConfirm('are you sure?', 'Confirmation Dialog', function(r) {
        if (r) doSomething();
    });
}

@klogan [comments]

I assume you got these from here?

The page gives you your answer: (look under Usage)

These methods do not return the same values as confirm() and prompt(). You must access the resulting values using a callback function. (See the demo for more details.)


@klogan

The point I'm trying to make is that there isn't really an easy way to accomplish what you want. You're trying to correlate procedural and event-driven programming -- something JavaScript doesn't help you do.

The simplest (though, risky) solution is to use a pseudo-infinite-loop. But, if callback never gets called, you now have an actual infinite loop. And, depending on the JavaScript engine, you might kill the browser waiting.

Point: Your best bet is to avoid this trying to force event-driven into procedural.

function confirm() {
    var result = false;
    var response = false;

    jConfirm('are you sure?', 'Confirmation Dialog',
      function(r) {
        result = r;
        response = true;
    });

    while(!response) continue; // wait
    return result;
}

Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • Thanks for the response, but I need the function to return the result from the callback function. So if the user clicks ok -> return true, if the user clicks cancel -> return false. Then this will work just like the built in confirm function. – AlignedDev Jan 12 '09 at 19:51
  • I did get the answer from their web page. – AlignedDev Jan 12 '09 at 19:59
  • and their demo code doesn't show how to use the confirmation results – AlignedDev Jan 12 '09 at 20:18
  • Thanks, I actually tried the while loop to test that solution, but IE will throw an alert dialog saying javascript is hanging. You're right I wouldn't want to do that. I'll wait to hear from the authors and post the solution. Maybe they hadn't finished it themselves. – AlignedDev Jan 12 '09 at 21:09
  • 4
    The infinite loop won't work. JavaScript is single-threaded; jQuery's confirm UI cannot even be interacted with whilst the while loop is spinning. – bobince Jan 12 '09 at 21:27
5

Technically, yes, but I wouldn't do that on a website.

Take a look at Narrative JavaScript, which is based off Narcissus.

Narrative JavaScript is a small extension to the JavaScript language that enables blocking capabilities for asynchronous event callbacks. This makes asynchronous code refreshingly readable and comprehensible.

Selenium uses this technology.


Update

Check out JavaScript Strands:

JavaScript Strands adds coroutine and cooperative threading support to the JavaScript language to enable blocking capabilities for asynchronous event callbacks. This makes code that utilizes asynchronous operation much more linear, readable, and manageable. Strands is built upon Narrative JavaScript written by Neil Mix, and much of Narrative JavaScript has remained in Strands including much of this documentation.

In JavaScript your code can't simply wait until an event has fired -- the event must always be handled by a separate, asynchronous event handler. Sometimes this is fine, but it often forces what ought to be a simple sequence of statements into gnarly contortions. It also breaks the ability to encapsulate functionality because calling functions must know to provide a callback handler. Strands provides the ability to suspend and resume threads of execution. Execution can suspend resume when the event is finished. This allows you to write hard-to-read asynchronous event handling in simple, linear, readable code that encapsulates implementation.

Greck
  • 580
  • 6
  • 15
Ates Goral
  • 137,716
  • 26
  • 137
  • 190
0

I would assume you'd have to grab the response like this. I don't think you need a callback.

function confirm() {
        var response = jConfirm('are you sure?', 'Confirmation Dialog');
        if (response) {
            alert(result);
        }
        else {
            //wait for response
            alert('hi');
        }
    }
Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
  • 1
    Unfortunately, the plugin does not return a variable. This was what I was expecting when I started working with it. – AlignedDev Jan 12 '09 at 19:46
0

I think I have come up with a possible solution to this problem. I was reading this article: http://treasure4developer.wordpress.com/2008/06/23/calling-postback-event-from-javascript/

Basically the idea is that you force the postback from javascript, at first I found that the postback would work but wouldn't call my button event, but after reading the article I found that I could detect if it was javascript postback and just call a method to do the processing

Regards DotnetShadow

0

How the dudes said, there is no way! but... how we use to say in my country (Brazil), le gambi:

we can do something like it:

<h:commandLink styleClass="linkValor xExcluir" value="x"  
                     onclick="if(confirmar('Confirmar excluir.','Deseja realmente excluir este registro?', this)) return true; else return false;"
                     action="#{mBeanPesquisarLinhas.excluir}"/>

and the javascript:

function confirmar(titulo, msg, elemento) { 

    if ($(elemento).attr('sim')) {      
        $(elemento).removeAttr('sim');      
        return true;
    } else if ($(elemento).attr('nao')) {       
        $(elemento).removeAttr('nao');      
        return false;
    } else {
        $("#dialog-confirm").html('<p>' + msg + '</p>').dialog({
            resizable : false,
            height : 200,
            modal : true,
            title : titulo,
            buttons : {
                "Sim" : function() {
                    $(this).dialog("close");
                    $(elemento).attr('sim', 'sim');
                    $(elemento).click();
                },
                "Não" : function() {
                    $(this).dialog("close");
                    $(elemento).attr('nao', 'nao');
                    $(elemento).click();
                }
            }
        });
    }

    return false;
}

it's the same problem but using jquery-ui.

Bye and I hope this can help somebody.

MaikoID
  • 4,359
  • 4
  • 25
  • 27
0

This thing works. Needs jQuery.

function myconfirm(kyssa, elm, e){ // neG
    if(jQuery('#confirmquestion').data('result')){
        var V = jQuery('#confirmquestion').data('result');
        jQuery('#confirmquestion').remove(); 
        return V == 'Y' ? true : false;         
    }else if(!jQuery('#confirmquestion').length){
        jQuery('body').append('<div id="confirmquestion">'+
        '<h4>Kinnitus</h4>'+
        '<div id="kyssa">'+kyssa+'</div>'+
        '<center>'+
        '<button onclick="jQuery(\'#confirmquestion\').data(\'result\', \'Y\');">Jah</button>&nbsp;'+
        '<button onclick="jQuery(\'#confirmquestion\').data(\'result\', \'N\');">Ei</button></div>'+
        '</center>');
        jQuery('#confirmquestion button').click(function(){
            jQuery(elm).trigger(e.type);
        })
    }       
    return false;
}

onChange="if(myconfirm(\'Saada kiri: \'+jQuery(this).find(\'option:selected\').html()+\' ?\', this, event)) { ... }"

CSS

#confirmquestion{
    border:1px solid #999;
    background:white;
    padding-bottom: 30px;
    position:fixed;
    width:300px;
    font-size:12px;
    top:45%;
    left:50%;
    margin-left:-150px;
}

#confirmquestion h4 {
    background:blue;
    color:white;
    margin:0;
    padding: 2px 5px;
    border-bottom:#777; 
    text-align:center;
}

#confirmquestion #kyssa {
    padding: 30px 25px;
}
Eonasdan
  • 7,563
  • 8
  • 55
  • 82
neG
  • 1
0

Think about callbacks as sending messages and it will result in better structure in your code.

Cris Stringfellow
  • 3,714
  • 26
  • 48