2

I have some set of code which I want to execute once a function gets completed and this set of steps and functions will be called on click of a button. Below is my code:

$scope.activetab = function (tabname, $event) {
   $.when(function () {
        showLoader();
        alert('done');
   }).done(function () {
        alert('next');
        if (tabname == 'General')
             $scope.GeneralAct = true;
        else if (tabname == 'Contact Information')
             $scope.ContactAct = true;
        else if (tabname == 'Position/Hierarchy')
             $scope.PositionAct = true;
        else if (tabname == 'Ids and Program Access')
             $scope.IdsAct = true;
        else if (tabname == 'Equipment')
             $scope.EquipmentAct = true;
        else if (tabname == 'Licensing')
            $scope.LicensingAct = true;
    });
};

and my showLoader function is as below:

function showLoader() {
    var dfd = $.Deferred();
    $('body').append('<div class="loader"></div>');
    dfd.promise();
}

but here alert('next') gets executed first and then alert('done') gets executed. What is the actual problem here? I am not pretty much sure about the way the promises work here!! Can anybody tell how to correct this?

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Guruprasad J Rao
  • 29,410
  • 14
  • 101
  • 200

1 Answers1

3

$.when() does not work properly because you are not returning a promise from the funtion that you pass it. But, showLoader() is not asynchronous so there is no need to use a promise with it at all.

Since there are no async operations shown in your code, you can just program synchronously like this:

$scope.activetab = function (tabname, $event) {
        showLoader();
        if (tabname == 'General')
             $scope.GeneralAct = true;
        else if (tabname == 'Contact Information')
             $scope.ContactAct = true;
        else if (tabname == 'Position/Hierarchy')
             $scope.PositionAct = true;
        else if (tabname == 'Ids and Program Access')
             $scope.IdsAct = true;
        else if (tabname == 'Equipment')
             $scope.EquipmentAct = true;
        else if (tabname == 'Licensing')
            $scope.LicensingAct = true;
};

function showLoader() {
    // this is a synchronous operation, so no need for promises here
    $('body').append('<div class="loader"></div>');
}

If there was an async operation inside of showLoader(), then to use it with $.when(), you'd have to do three things you aren't currently doing:

  1. You'd have to return a promise from showLoader().
  2. You'd have to resolve that promise when showLoader() was complete.
  3. You'd have to pass that promise to $.when().

$.when() works with async operations by passing it one or more promises and it then monitors when those promises get resolved and resolved it's own promise only when all the promises you passed it have been resolved.


Since it now appears that the real problem you want to solve is how to force a repaint before your other code runs, you can see how to do that in this answer: When does the DOM repaint during Javascript routines?

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I could have worked without `$.when` but the problem here is the `html rendering`!! It will not show loader until the rendering is completed,since I have to render huge amount of html, which makes user thinks that click has not happened since the page becomes irresponsive! However, it will show the loader if I keep an `alert` after `showLoader()` function call without using `$.when` as mentioned in your answer! That's why I tried to come up with promises! Any work around for this?? – Guruprasad J Rao May 26 '15 at 09:00
  • 1
    @GuruprasadRao - Making the rendering show is a completely different issue. Next time, please state the actual core problem in your question rather than a problem you ran into with your particular solution which, in this case, happens to be going the completely wrong direction. I will add some info to may answer now about the rendering issue. FYI, not posting about the real problem is what is called the [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) and is a pretty sure way to make it impossible for anyone to give you the best answer. – jfriend00 May 26 '15 at 09:04
  • @GuruprasadRao - I added a link to my answer for how to solve the repaint issue. – jfriend00 May 26 '15 at 09:08
  • @jfried00.. Sorry for that!! I will check the link given by you. But here my doubt was regarding the promises itself because as of my knowledge `$.when` and `.then` should work according to what I've tried, yea missed some part on that and may be that's reason for not working and you explained it. So I'll accept this as answer!! Thank you for your time.. :) – Guruprasad J Rao May 26 '15 at 09:12
  • 1
    @GuruprasadRao - OK, glad you got it sorted out. – jfriend00 May 26 '15 at 09:36