jquery-uijquery-ui-dialogjquery-deferredjquery-chaining

Open jQuery UI Dialogs One After Another


I have multiple jQuery UI dialogs that I would like to show one after another (one closes, the next in line opens). Currently, they all display modal, but one of the back ones is larger, and it looks bad/confusing in my opinion.

I would normally have the close functions of one dialog open the next, but these dialogs are called from separate functions, and they are kind of dynamic in the sense that not all of them are always displayed based on certain criteria.

I am contemplating a way to use $.Deferred, but am unsure if this would work as my understanding is it works more for things like AJAX calls.

Here is an (extremely) simplified example of how the code could be structured as-is.

<script>
function displayAlert1(){
    $('<div/>', {text: 'Alert 1!'}).dialog({
        modal: true,
        autoOpen: true,
        width: 400,
        buttons: { OK: function(event, ui){ $(this).dialog('close'); } }
    });
}
function displayAlert2(){
    $('<div />', {text: 'Alert 2!'}).dialog({
        modal: true,
        autoOpen: true,
        width: 200,
        buttons: { OK: function(event, ui){ $(this).dialog('close'); } }
    });
}

$(function(){
    // These are actually met from data passed by AJAX
    var condition1 = true;
    var condition2 = true;
    $('a').live('click', function(event, ui){
        if(condition1) displayAlert1();
        if(condition2) displayAlert2();
    }
});
</script>

<!-- The links are actually dynamically produced from AJAX, thus the live() event handler -->
<a>Click Me!</a>

jsFiddle

My thinking is maybe I can have each alert function return a reference to the dialog element, or a $.Deferred object, but I'm not sure how to implement chaining from the main execution part (where the conditions are checked and the functions are called).

I would also like to make sure it chains to the next dialog no matter how the dialog before it is closed; whether by the X, by the 'close' method, or 'destroy' method.

Thank you for any input.


Solution

  • After thinking about the situation, I came up with the simplified method of using a stacked queue. I imagine I could have used the $.Deferred object, but it would be a little more complicated, and it essentially would be a stack in the end.

    Below is my code. I basically initialized an array to use as my stack, and I will have each function push the dialog element into the stack. I bind into the close event of all future dialogs, and have it open the next one in the queue.

    There are some obvious optimizations to do, but this is the barebones that works as I want.

    function displayAlert1(){
        return $('<div/>', {'class': 'alerts', text: 'Alert 1!'}).dialog({
            modal: true,
            autoOpen: false,
            width: 400,
            buttons: { OK: function(event, ui){ $(this).dialog('close'); } }
        });
    }
    function displayAlert2(){
        return $('<div/>', {'class': 'alerts', text: 'Alert 2!'}).dialog({
            modal: true,
            autoOpen: false,
            width: 200,
            buttons: { OK: function(event, ui){ $(this).dialog('close'); } }
        });
    }
    
    $(function(){
        // These are actually met from data passed by AJAX
        condition1 = true;
        condition2 = true;
    
        // Dialog stack
        dialogs = [];
    
        $('a').live('click', function(event, ui){
            if(condition1) dialogs.push(displayAlert1());
            if(condition2) dialogs.push(displayAlert2());
    
            // Grab the next dialog in queue
            d = dialogs.shift();
            // Check if it is valid, and open it
            if(d && d.dialog){
                d.dialog('open');
            }
        });
    
        $('.alerts').live('dialogclose', function(event, ui){
            // Grab the next dialog in queue
            d = dialogs.shift();
            // Check if it is valid, and open it
            if(d && d.dialog){
                d.dialog('open');
            }
            // Return false, or the close button (X) will glitch and re-create dialogs
            return false;
        });
    });
    

    jsFiddle