Question

I have a jq replacement of the standard confirm dialog.

I am allowing the user to pass in a function that will be called if the user clicks on ok.

The passed in function may call a long running async task like an ajax call, sometimes not, I want to cater for both.

I used this solution as a base (https://stackoverflow.com/a/19374933)

What I want to achieve is something like this:

MyConfirmation('A Title', 'A message to the user', function() {
    $.get('/some/bigdata/longrunning');
}
).then(function() {
    // add to dom here
});

This is MyConfirmation:

MyConfirmation = function (title, message, ok) {
    var d = $.Deferred();
    $('<div/>')
        .text(message)
        .dialog({
                    buttons: {
                "Ok": function () {
                    if($.isFunction(ok)) {
                        ok.apply();
                    }
                    $(this).dialog("close");
                    d.resolve(true);
                    return true;
                },
                "Cancel": function () {
                    $(this).dialog("close");
                    d.resolve(false);
                    return false;
                }
            },
            close: function(event, ui) {
                $(this).remove();
            },
            resizable: false,
            draggable: false,
            width: 'auto',
            title: title,
            modal: true
        });

    return d.promise();
};

I want to ideally combine with my deferred which returns true or false to indicate if the user clicked ok or cancel.

I know I can use the .done method on the promise returned from $.get but how would I make my solution work

Was it helpful?

Solution

I am allowing the user to pass in a function that will be called if the user clicks on ok.

Don't. Just remove that ok parameter from the MyConfirmation function, and only return the promise for the button clicks. The user can then chain his function on that if he wants - or do even more.

Your call should rather look like this:

MyConfirmation('A Title', 'A message to the user').then(function(okPressed) {
    if (okPressed)
        return $.get('/some/bigdata/longrunning');
}).then(function(longruningResult) {
    // add to dom here
});

You might also reject() the promise when the Cancel button is pressed, then you don't need that boolean okPressed check and could use a separate error handler instead.

OTHER TIPS

I think you should use the ajax call as a returned promise :

MyConfirmation('A Title', 'A message to the user', function() {
    return $.get('/some/bigdata/longrunning');
}
).then(function() {
    // add to dom here
});

MyConfirmation function:

MyConfirmation = function (title, message, ok) {
    var d = $.Deferred();
    $('<div/>')
        .text(message)
        .dialog({
                    buttons: {
                "Ok": function () {
                    if($.isFunction(ok)) {
                        ok().then(function() {
                            d.resolve(true);
                        });
                    }
                    $(this).dialog("close");
                    return true;
                },
                "Cancel": function () {
                    $(this).dialog("close");
                    d.resolve(false);
                    return false;
                }
            },
            close: function(event, ui) {
                $(this).remove();
            },
            resizable: false,
            draggable: false,
            width: 'auto',
            title: title,
            modal: true
        });

    return d.promise();
};

This adds a condition to resolve the dialog deffered, from the ajax promise itself

Disclaimer : untested :)

Following on from Pandaiolo's response, I realised I was supposed to return the ajax call in my calling function. That and the chaining of my own deferred when the passed in function completed.

A small tweak to catch those instances when the passed in function does not return a deferred (by using $.when) and it works (see How can I determine if a jQuery object is deferred?)

MyConfirmation becomes:

MyConfirmation = function (title, message, ok) {
    var d = $.Deferred();
    $('<div/>')
        .text(message)
        .dialog({
                    buttons: {
                "Ok": function () {
                    if($.isFunction(ok)) {
                        $.when(ok.apply()).then(function() {
                            d.resolve(true);
                        });
                    } else {
                        d.resolve(true);
                    }
                    $(this).dialog("close");
                    return true;
                },
                "Cancel": function () {
                    $(this).dialog("close");
                    d.resolve(false);
                    return false;
                }
            },
            close: function(event, ui) {
                $(this).remove();
            },
            resizable: false,
            draggable: false,
            width: 'auto',
            title: title,
            modal: true
        });

    return d.promise();
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top