-1

My problem is pretty simple and I think lot of programmers already must have faced this. I am using angularjs and my javascript looks as follow:

controller('myController', function())
{
    if(validateForm())
    {
        //do after-validation stuff
    }
    validateForm = function()
    {
        var val = undefined;
        $http.get('api/validate/').
        success(function(data){
            val = true;
        }).
        error(function(data){ 
            val =false;
        });
        while(!val)
        { // loop over till val has value
        } 
        return val;
    }
}

I have two questions:

1) when I make http call it returns a promise object and it resolves to either success or error function. If that is the case then the while loop in this code should not be infinite, but it is. By debugging I found that if I assign a value to variable 'var' then only the http call is made i.e when the loops ends. why http call, being a deferred call, waits on the while loop to finish?

2) If I remove the while loop, no matter what the value of 'var' is, the function returns. How can I make it return only if 'var' is defined?

sweetcode
  • 159
  • 1
  • 12
  • could u please describe the first one a little bit ? :) – Kalhan.Toress Oct 05 '14 at 04:22
  • Hi Kalhano Torres Pamuditha, the scenario itself is simple, what I am trying to achieve is A calling B and B returning a value based on which A does something or moves on. – sweetcode Oct 05 '14 at 05:18
  • possible duplicate of [How to return the response from an Ajax call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – John Dvorak Oct 05 '14 at 05:26

3 Answers3

1

JavaScript is single threaded, so the http success/failure never get executed because the while loop is going. This is causing your infinite loop.

Return the promise and use that in the calling function.

marneborn
  • 699
  • 3
  • 9
  • If I return promise to the calling function and do a promise.then(...) there then the control will move on irrespective of the return value from the http call. So anything after prmosie.then(..) statement will be executed which I want to avoid. I can put my entire logic inside .then() but that makes things very confusing. Doing if(fnCalll()) looks simpler than promise.then(). – sweetcode Oct 05 '14 at 05:11
  • OK, the sugar success and error methods added to http calls don't have a value associated with them (ie there is no return in the wrapper function) so the value on the next promise will be undefined (I'm not at a computer so this may not be correct). Either skip the sugar methods ie use .then, or, in the success, set a variable in the closure and add a .then that pushes that value to the next promise. – marneborn Oct 06 '14 at 03:55
0

Well usually ajax calls like these are not synchronous, having said that, when your while loop is hit your variable val is not yet set. What you should do is, just call a function in either success or error case and that function should have your while loop. Or try to make async ajax call which I am not sure if possible with selected method. So your new code will be something like

function mycallback(someval){
    while(!someval)
    { // loop over till val has value
    }
}
controller('myController', function())
{
    if(validateForm())
    {
        //do after-validation stuff
    }
    function()
    {
        var val = undefined;
        $http.get('api/validate/').
        success(function(data){
            val = true;
            mycallback(val); 
        }).
        error(function(data){ 
            val =false;
            mycallback(val);
        });


    }
}

depending on your need you need to change flow to meet this sync/async call. I don't recommand syncing the call as it slow down the execution for time your get ajax response. You should practice to use Async call only.

Sumit Gupta
  • 2,152
  • 4
  • 29
  • 46
  • Hi Sumit, in this case won't the if() condition will always turn out to be false ? – sweetcode Oct 05 '14 at 05:15
  • Well, I am not sure why you have that if, and hence I didn't touch it. I guess it is to validate other field except the validation you need from ajax, if not, then put it in callback function. – Sumit Gupta Oct 06 '14 at 10:15
0

Refactor, and use the .then

angular.module("myModule")
.controller("myController", ["$scope", "$http", function ($scope, $http) {

    var controller = this;

    angular.extend(controller, {
        // ...
        submit : submit,
        handleSuccess : function () { /* ... success */ },
        handleError   : function (err) { /* error */ }
    });

    function submit (form) {
        validateForm(form)
            .then(controller.handleSuccess, controller.handleError)
            .then(controller.cleanUp);
    }

    function validateForm (form) {
        return $http.get("...").then(function (response) { return response.data; });
    }

}]);

It should all be readable, now. Additionally, the logic doesn't go inside of "success", instead it goes inside of subsequent .then calls, so you can keep your submit clean and readable.

But you can not ever do something like

while (true) {
}

or

for (var i = 0; i < 10000000; i += 1) { }

All you are doing is locking your browser, preventing people from using the page.
You can't animate CSS, you can't read AJAX values, you probably can't even close the tab (depending on the browser).

Everything should either be reactive (event-based) or asynchronous, using callbacks or promises.

Norguard
  • 26,167
  • 5
  • 41
  • 49