Skip to content Skip to sidebar Skip to footer

Dojo Using Deferred Functions To Get Data In Ajax Callback Function

I have a function with a return however in the function there is an async request which holds the value that is suppose to be returned by the function. I understand with the nature

Solution 1:

Devdar, you are making heavy wether out of something quite simple. In particular, you don't need to loop through an object to access one of its properties, and the variable hasErrors is not really necessary.

Your code should simplify to something like this :

functionPostInformation() {
    var $containers = $("#container1, #container2");
    varEmployee = {
        //data
    };
    return dojo.xhrPost({
        url: 'hello',
        content: Employee
    }).then(function(data) {
        data = JSON.parse(data);
        var formErrors = data.formErrors;
        if(formErrors.errors) {
            $containers.each(function(i, c) {
                $(c).children().each(function(wid) {
                    var val = formErrors[wid.id],
                        myWidget;
                    if(val) {
                        myWidget = dijit.byId(wid.id);
                        myWidget.validator = function() {
                            this.set("invalidMessage", val);
                        };
                        myWidget._hasBeenBlurred = true;
                        myWidget.validate();
                    }
                });
            });
            //Send an enhanced error object down the "error" route throw $.extend(formErrors, {
                'message': 'PostInformation(): validation failure'
            });
        }
        //Send the data object down the "success" route return data;
    });
};

PostInformation().then(function(data) {
    console.log('PostInformation(): everything went OK');
    //access/process `data` here if necessary//and/or just display a nice "success" message to the user
}, function(err) {
    console.error(err.message);
});

Barring mistakes on my part, this code should do everything you want and more. As with your own code, it processes the server's JSON response and returns a Promise, but that's where the similarity stops.

In your code, you seek to return a Promise which is eventually resolved with a boolean to indicate whether or not errors were detected. Whilst this will (if correctly written) meet your immediate needs, it is not the best Promise logic.

In my code, the Promise is resolved only if validation succeeds and rejected if validation fails for whatever reason. Not only is this logically correct behaviour for a Promise (success goes down the success route, and errors go down the error route) but as a bonus should (see note below) also allow you to pass more information to whetever function(s) eventually handle errors. I choose to pass the whole formErrors object enhanced with an error message, thus providing a great deal of freedom in the error handler to display/log/etc as much or as little as is appropriate, and with virtually no assumption inside PostInformation() as to what will happen subsequently. You currently believe that you will only read and act on the boolean formErrors.errors but it could be beneficial to pass as much error data as possible thus allowing yourself the freedom to change your mind at a later date without needing to change anything in PostInformation().

In this regard you can think of PostInformation() as an agent of the server-side service; and like that service, it can be written with incomplete knowledge (or maybe no knowledge at all) of how the (promise of) data/errors it delivers will be used by "consumer code".


NOTE: I have to admit that I'm not 100% familiar with Dojo's Promises, so I'm not sure that a JS plain object can be thrown in the way I indicate. I have found evidence but not proof that it can. For that reason, I am cautious above in saying "your code should simplify to something like this" Anyway, that issue aside, the principle of sending success down the success route and errors down the error route should still apply.

Solution 2:

I'd suggest this where you create your own Deferred() object, return it from your PostInformation() function and then register .then() handlers on it so you can pick up the resolve or reject on your own Deferred object that happens inside the PostInformation() function.

The way you had it you were creating your own Deferred() object, but then immediately overwriting it with the xhrPost return result which meant def is now something else and you weren't returning your Deferred from PostInformation() so it can be used outside that function to track the progress.

functionPostInformation() {
    var hasErrors = false;
    var containers = [dijit.byId("container1"), dijit.byId("container2")];
    varEmployee = {
        //data
    };
    var def = new dojo.Deferred();
    dojo.xhrPost({
        url: 'hello',
        content: Employee,
        load: function (data) {
            formErrors = {
                "errors": true,
                "fName": "123",
                "surname": "456",
                "oNames": "789",
                "bSurname": "784585"
            };
            //formErrors = (JSON.parse(data)).formErrors;
            $.each(formErrors, function (key, value) {
                if (key == 'errors') {
                    hasErrors = value;
                    //console.log('hasErrors set to '+value);
                }
            });
            if (hasErrors == true) {
                for (var i = 0; i < containers.length; i++) {
                    var processingContainer = containers[i];
                    dojo.forEach(processingContainer.getChildren(), function (wid) {
                        var widgetName = wid.attr('id');
                        $.each(formErrors, function (key, value) {
                            if (key == widgetName && value.length > 0) {
                                var myWidget = dijit.byId(widgetName);
                                //var wdgName = dijit.byId(widgetName).attr("id");var myWidgetValue = value;
                                myWidget.validator = function () {
                                    //console.log('Attribute Name is :' + wdgName + ' Error Value is : ' + myWidgetValue);//console.log(wdgName + " : "+myWidgetValue);this.set("invalidMessage", myWidgetValue);
                                };
                                myWidget._hasBeenBlurred = true;
                                myWidget.validate();
                            }
                        });
                    });
                }
            }
            console.log(hasErrors);
            def.resolve(hasErrors);
        },
        error: function (err) {
            console.log(err);
            def.reject(err);
        }
    });
    return def.promise;
};

PostInformation().then(function (data) {
     console.log('In the then function');
     // process data value here which will contain the value you resolved with
  }, function(err)
      // process an error in the ajax result here
});

Solution 3:

I think this is more of an issue with design of the function then.

Since the xHR call is asynchronous, the postInformation shouldn't really return anything unless it's the Deferred object itself. An alternative option is to have postInformation do some sort of event publishing (dojo/topic), that other functions will subscribe to and know how to handle said events.

Post a Comment for "Dojo Using Deferred Functions To Get Data In Ajax Callback Function"