3

I would like to implement dependency calls of Deferred/Promise. The problem is I don't understand how to make calls step-by-step for array of handlers that contains async calls e.g.

I have global object :

var options = {
    additionalHandler: []
    main : null
}

Then add main function and handlers that add in strong sequential and also need to call in this sequences

options.main = function(that, data){
    var that = this; //Todo: fix this should be button
    //Do some staff
}

var dialog = $(somedialog).dialog({
    autoOpen: false,
    modal: true,
    buttons: {
        "OK": function() {                            
            //There is the place where i have wait user answer to invoke innerDeferred.resolve(true) that is have to affected on global Deferred
            $(this).dialog("close");
        }
    },
    close: function () {
        //innerDeferred.resolve(false);
    }
});

options.additionalHandler.push(function(){
    dialog.dialog("open");
})

Than when button click happen i run/wait all handlers and then execute main function if all of handlers returns true

$("#someButton").on("click", function () {
    var self = this;
    if(typeof options !== "undefined"){
        var deferred = $.Deferred();
        if (options.additionalHandler &&  options.additionalHandler.length) // if we do not have(collect) any handlers we don't ran it all
        {
            $(options.additionalHandler).each(function () {
                if (typeof this !== "undefined" && typeof this === "function") {
                    deferred.then(this( /*??? deferred or innerDeferred */));
                }
            });
        }
        deferred.done(function (def) {
            if(def) // if all steps from all inner steps return true 
                options.main(self , someData));
        });               
    }
}

Which means I have one main handler that depend on additional handler answers that possible not existed (if not existed we just go to main handler), and the questions is how implement dependency on async inner deferred call result which is should run step-by-step(dialog box in our case wait user answer and go to another dialog box or possible ajax calls).

Update1:

From the top up to bottom this is pseudo implementation(code) and also not working

How this works(required):

user => add some itemp to backet
backet <= knows about some discount if user purchase 2 items and register new pop-up that says if you add 2 you'll have 50% sale.
user => add another item to backet 
backet <= this item will not available till next week, register another pop-up.
user = > push Order
Order => (pop-up) Discount if 2 do you (Yes-break /No -continue) => Item available on next week will wait ( Yes - continue/ No- break) => if (all.Continue) => push Order.

all works as waterfall, and I don't see the pros/cons with deferred/promise

Alex P
  • 31
  • 4
  • Thank you @Randy, and exuse me, fixed `dialog` declaration and also `options.additonalHandler` outside – Alex P Apr 19 '18 at 16:18
  • Thanks! next question: In this code, there is only ever a single model reference pushed in to the array. Where is the code that pushes other async callbacks in the array? – Randy Casburn Apr 19 '18 at 16:19
  • @RandyCasburn I guess its no matter for now - you can make `var dialog1 = ... ` and then make ` options.additionalHandler.push` for this one new dialog – Alex P Apr 19 '18 at 16:22
  • 1
    First of all, avoid the [deferred antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! You only need promises here. – Bergi Apr 19 '18 at 16:28
  • Take a look at https://stackoverflow.com/questions/39453976/confirm-form-submit-with-jquery-ui – Twisty Apr 24 '18 at 07:51
  • Thank you @Twisty, but this one fixed, see my answer at bottom. – Alex P Apr 24 '18 at 10:16

2 Answers2

1

There are couple of issues in the code.

Your deferred variable is still referring to the original Deferred which is empty, you need to update your deferred everytime you are adding a callback.

deferred = deferred.then(this( /*??? deferred or innerDeferred */));

Your check for true inside done method, you need to make sure that all of your callbacks are returning true (at least the last one).

If you are using async callbacks, make sure they are returning deffered instances which return true.

Last thing, the first param you pass to the options.main doesn't matter as you are overwriting it inside the method.

AvcS
  • 2,263
  • 11
  • 18
0

Here is the solution with sequence async operation implement on promises:

Get from here

<!DOCTYPE html>
<html>
    <head>
        <script src="https://code.jquery.com/jquery-1.12.4.js" integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU=" crossorigin="anonymous"></script>
        <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js" integrity="sha256-0YPKAwZP7Mp3ALMRVB2i8GXeEndvCq3eSl/WsAl1Ryk=" crossorigin="anonymous"></script>
        <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" crossorigin="anonymous">

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">        <!-- Latest compiled and minified JavaScript -->
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

        <script>
            $(function() {
                var options = {
                    additionalHandler: [],
                    main : null
                }                

                options.main = function(confirmed){                    
                    $("#result").html("Confirmed: " + confirmed);
                };

                options.additionalHandler.push(function(resolve, reject, data){
                    var dialog1 = $("#dialog1").dialog({
                        autoOpen: false,
                        modal: true,
                        buttons: {
                            "OK": function() {                            
                                resolve(true);
                                $(this).dialog("close");
                            }
                        },
                        close: function () {
                            resolve(false);
                        }
                    });
                    dialog1.dialog("open");
                });

                options.additionalHandler.push(function(resolve, reject, data){
                    var dialog2 = $("#dialog2").dialog({
                        autoOpen: false,
                        modal: true,
                        buttons: {
                            "OK": function() {                            
                                resolve(true);
                                $(this).dialog("close");
                            }
                        },
                        close: function () {
                            resolve(false);
                        }
                    });
                    dialog2.dialog("open");
                });

                Array.prototype.chainExecute = function(data){
                    var array = this;
                    var results = [];
                    return array.reduce(function(previous, current) {
                        return previous.then(function(result) {
                            return new Promise(function(resolve, reject) {
                                current(resolve, reject, data); 
                            }).then(function(result) {
                                results.push(result);
                                return results;
                            });
                        });
                    }, Promise.resolve());
                };

                $("#orderPush").on("click", function () {
                    var self = this;
                    if(typeof options !== "undefined")
                    {
                        options.additionalHandler.chainExecute("Blah").then(function(result) {
                            options.main(result);
                        }, function(reason) {
                            options.main(reason);
                        })                                        
                    }
                });
            });        
        </script>
    </head>
    <body>
        <div id="dialog1" style="display: none">
                <div>Discount if 2 items!</div>
        </div>
        <div id="dialog2" style="display: none">
                <div>Been available on next week!</div>
        </div>

        <button type="button" class="btn btn-primary" id="orderPush">Process order</button>
        <p><strong id="result"></strong></p>
    </body>
</html>
Alex P
  • 31
  • 4