Indyarocks
Indyarocks

Reputation: 663

How to check promise returned value and take action in angularjs?

I want to check for Internet connection by hitting a pixel on public cloud. Based on the response I want to show an alert whether user is connected or not to Internet. Following is the code for pixel load($q is injected in the service, which has below function):

  hasInternetConnection = function(pingUrl){
var img,
  pingUrl = Constant.ImageUrl;

var deferred = $q.defer();

img = document.createElement('img');
img.onerror = deferred.reject(false);
img.onload = deferred.resolve(true)
img.src = pingUrl;

return deferred.promise
}

Now based on its return value I want to do following:

var con = hasInternetConnection()
if(!con){
  alert('No connection')
}

But this is not working. Any suggestions?

How can you test the alert popup in unit testing?

Thanks.

Upvotes: 1

Views: 799

Answers (2)

Roamer-1888
Roamer-1888

Reputation: 19288

To overcome issues you probably aren't even aware of, try Offline (3kb minified and compressed), or at least read the README.md.

You'll see that the author moved away from hitting a cloudfront hosted file in favour of (by default) '/favicon.ico' (on same origin) or anything that will give a 204 (No Content).

The image technique is deprecated because a 404 (File Not Found) can't be distinguished from a genuine connection issue. From v0.7.0, Offline checks with an XHR, under which even a 404 (or 204) means "connected".

With Offline, you also get some great sugar such as 'checkOnLoad', 'interceptRequests' and 'reconnect' options.

Upvotes: 0

jfriend00
jfriend00

Reputation: 707686

There are many things wrong in both your understanding of how to use a promise for this task and even how to assign callbacks to the image.

Here's a cleaned up version of your function:

function hasInternetConnection() {
    var timer, timeoutTime = 4000;
    var defer = $q.defer();

    var img = new Image();
    img.onload = function() {
        clearTimeout(timer);
        defer.resolve(true);
    }
    img.onerror = img.onabort = function() {
        defer.resolve(false);
    }
    img.src = Constant.ImageUrl + "?rand=" + 
        (Math.random() + "").replace(".", "") + "_" + (new Date().getTime());

    // set max time to wait
    timer = setTimeout(img.onerror, timeoutTime);
    return defer.promise;    
}

hasInternetConnection().then(function(connected) {
    if (connected) {
        // have internet here
    } else {
        // no internet here
    }
});

Working demo: http://jsfiddle.net/jfriend00/2xr4rzqq/

Summary of changes/fixes:

  1. Add cache busting value to URL so you won't accidentally fetch the image from the cache.
  2. Change use of the promise to a .then() handler.
  3. Correctly assign onerror and onload to be actual function references that can be called later.
  4. Add timeout because system timeout is unknown so this gives you more control over how long to wait.
  5. Change both resolutions to use .resolve() since it seems easier for the caller to just check the promise value boolean rather than have two handlers. This is purely a design choice.
  6. Remove pingUrl argument since you weren't using that argument
  7. Uses new Image() instead of document.createElement("img")
  8. Include onabort handler for completeness.

Upvotes: 3

Related Questions