Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript promise .catch not working

Tags:

javascript

EDIT: SEE THE ANSWER BELOW

I have a function:

dataFactory.getCurrentStepId(wf.identifier, ctx.identifier)
   .then(function (data) {
      console.log('then');
      $timeout(function () {
      $("#app-node-" + data.identifier)
           .parent().parent().css("border", "5px solid green");
      });
    })
    .catch(function () {
      console.log('error');
      alert('Error!')
      });

The getCurrentStepId has an exception, and I see the error printed on the console for the AJAX request it sends, but my alert and console.log don't fire in the catch.

Any ideas why? Here is the stuff it's calling:

app.factory('dataFactory', function ($http, $q) {
    var _baseUrl = webServiceContext;
    var _doGet = function (endpoint) {
        var deferred = $q.defer();
        $http.get(_baseUrl + '/' + endpoint).then(function (response) {
            deferred.resolve(response.data);
        });
        return deferred.promise;
    };

    var getCurrentStepId = function (wid, cid) {
        return _doGet('wf/step/' + wid + '/' + cid);
    };
})

Here is the answer

@Blunderfest almost got it right:

 $http.get(_baseUrl + '/' + endpoint).then(function (response) {
            deferred.resolve(response.data);
        }).catch(function(e){return deferred.reject(e);});
like image 223
mikeb Avatar asked May 20 '26 05:05

mikeb


1 Answers

Make sure you return a rejected promise in your catch blocks. So this:

$http.get(_baseUrl + '/' + endpoint).then(function (response) {
        deferred.resolve(response.data);
    })

Should be this:

$http.get(_baseUrl + '/' + endpoint).then(function (response) {
        deferred.resolve(response.data);
    }).catch(function(e){
         return $q.reject(e);
    });

Actually, you can use $q.reject as a shorthand for rejecting a promise, so I think it's a correct answer :). You can also use return $q.when(response) as a shorthand for deferred, resolve and all that.

I recommend reading: $q.defer: You're doing it wrong

Really, I would re-organize your code to follow a few best practices on promises, especially in angular. It's better to return the $http request itself (which is a promise):

app.factory('dataFactory', function ($http, $q) {
    var _baseUrl = webServiceContext;
    var _doGet = function (endpoint) {
        // Returns the promise wholesale.
        return $http.get(_baseUrl + '/' + endpoint).then(function (response) {
            return response.data;
        }).catch(function(e){
            // ensures the returned promise is rejected up the chain.
            return $q.reject(e);
        });
    };

    var getCurrentStepId = function (wid, cid) {
        return _doGet('wf/step/' + wid + '/' + cid);
    };
})

Angular Docs for $q methods:

reject(reason) – rejects the derived promise with the reason. This is equivalent to resolving it with a rejection constructed via $q.reject

The reason you need to do this is that if you do not catch errors and reject promises at lower levels, the promise chain up the line will not know the promise is rejected and treat it as a success.

like image 133
Blunderfest Avatar answered May 21 '26 19:05

Blunderfest