Offline Web Apps – Part 2: navigator.onLine

In Part 1 of this two part blog post, I covered a few of the basic fundamentals of offline web apps. Specifically, how to use a cache manifest to cache application resources offline in the browser. In part 2 we will dive into the how to ensure your application is intelligent enough to handle offline scenarios using navigator.onLine.

Meet navigator.onLine

Caching application resources is a nice feature provides end users with the ability to have client side interactions with your application while they are offline. But what happens when your application needs to communicate with a server? To do so, you need to write javascript code that will take into account how to handle user driven events based on online/offline status. With the HTML5, there is a helpful state property of the Navigator object onLine along with two events that get fired (ononline/onoffline) when the connection status changes.

A Real-world Example

Let’s say for example you have a client side application where users enter large amounts of text content that gets saved to a server somewhere. In order to prevent users from losing work by an unintended browser close, you want to occasionally “autosave” their data every 30 seconds. This code might look something like this:

window.addEventListener('load', function () {
    var saveInterval = setInterval(function () {
        // Function call (XHR etc) to save data goes here
        ...        
    }, 30000) // Call this function every 30 seconds
});

Unfortunately, as straightforward as this implementation is, it leaves some pretty big gaps:

  • The function call to save data will repeat every 30 seconds regardless of success/failure
  • Users have no idea whether or not their data is indeed being saved to the server

Let’s fix this by using navigator.onLine and the ononline/onoffline events:

window.addEventListener('load', function () {           

    function updateOnlineStatus() {
        var condition = navigator.onLine ? "online" : "offline",
            saveInterval = null;
        if (condition === "online") {
            // Make update to UI here to let user know they are online and autosave is available
            ...
            ...
            saveInterval = setInterval(function () {
                    // Function call (XHR etc) to save data goes here
                       ...
                       ...
                    }, 30000)
                }
                else {
                    // Make update to UI here to let user know they are offline and are not autosaving
                    ...
                    ...
                    // Stop the interval from repeating until connectivty is resolved
                    clearInterval(saveInterval); 
                }
            }

        // Setup event listeners for when online/offline status changes
        window.addEventListener('online', updateOnlineStatus);
        window.addEventListener('offline', updateOnlineStatus);

        // Make initialization call to updateOnlineStatus
        pdateOnlineStatus();
});

With the code above, we have pretty solid coverage for when (and when NOT) to save changes based on connection status. As you can imagine though, the more complex an application is, the more complex these scenarios might become.

Additional Considerations and Resources

Like any other that gets executed in the browser, there are some subtleties to watch out for when it comes to cross browser compatability. At this time of this writing Firefox ignores actual network connectivity and instead triggers on the browser’s “Work Offline” mode. In addition, some browser/operating system combinations may not be intelligent enough to determine the difference between a true network connection and a local network adapter (virtual) showing an online status. For more information, please take a look at the following links:

Offline Web Apps – Part 1: Cache Resources

"No internet connection"

Offline web apps seems like a contradictory notion. After all, the web is based on the interconnectivity of devices. However, as we push the limits of when and where users access web content, “offline” web applications are drawing an increased demand. By taking advantage of a few different browser features (like window.applicationCache or navigator.onLine) providing dual mode (online/offline) applications an easier than expected task.

Basics of an Offline Application

Dual mode web applications at the bare minimum must satisfy two fundamental tasks:

  1. Caching of application dependent resources
  2. Be intelligent enough to handle both online and offline scenarios

Depending on the complexity of your web application, these two fundamentals may have varying levels of difficulty but the core concepts are the same.

Cache Application Resources

For initial load of an application, end users must have an online connection to access resources from the server. It is at this time where you can configure your application to let the browser know what files to keep a copy of locally in case your connection is dropped. This is done by using a cache manifest. The cache manifest is a simple text file with an “appcache” extension referenced as an attribute to your top level html tag.

<html manifest="manifest.appcache">
    <head>
        ...
    </head>
    <body>   
        ...
    </body>
</html>

At the most basic level your cache manifest file should list the files required to run your application in an offline mode under a “CACHE MANIFEST” header. These files will be stored locally on the device and the next time an application is accessed, the browser will know to use the cached file if available. (Note: This is also a very helpful tool for improving online application performance.)

CACHE MANIFEST
index.html
scripts/app.js
scripts/data.js
css/app.css
images/logo.png
...

For more information on using a cache manifest, check out Appcache Facts.

Part 2: Handle Offline Scenarios

Unlike setting up an application cache, configuring your application to handle offline scenarios is much more application specific in it’s implementation. In Part 2 of this post, I’ll cover how to handle those scenarios.

Ready to see more? Check out Part 2 of this post learn about navigator.onLine.

HTML5 Download Attribute: Success!

HTML5 Download Attribute Success Meme

Providing direct and easy download of files can be simplified using the HTML5 download attribute. Historically, forcing a browser to save a file has been an over complicated programming task. New HTML5 specifications have identified this gap in browser technology and have mapped out a straightforward approach to downloading resources using the new download attribute on anchor and area elements. In this post, I will briefly outline the challenges that developers had before the download attribute was available and then show how simple it is to implement.

Direct Download Challenges

Historically, there have been a number of different methods developers could try to employ to force a file to be downloaded in the browser. One popular choice is to use JavaScript to open a new window pointed at the file. Unfortunately, if the Content Type header of the HTTP response from the server is a MIME Type that the browser knows how to handle, the browser will simply open the file in the newly opened browser window. This approach can work for files that a browser is not used to handling (executables etc.) but will not work for common web files like images.

docuement.getElementById("download-button").addEventListener("click", function() {
            window.open(urlToFileLocation);
        });

Another more complicated approach involves writing server side code (C#, PHP, Java) that would receive an HTTP request, process it based on whatever logic is needed, and return a response that included the file with a Content-Disposition field set to attachment. This is a more reliable approach and can handle any file type the server is capable of serving up, but requires access to server side code and greater level of effort.

// ASP.NET C# Example
Response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
Response.ContentType = "application/octet-stream";
Response.WriteFile(filePath);
Response.Flush();
Response.End();

The download attribute

(At the time of this writing, the feature is not available in IE or Safari. Click here for existing support.)

Thankfully, with new HTML5 specifications for Downloading Resources, this additional effort can now be avoided by adding a single download attribute to any link.

<a href="download-success.jpg" download>Download Meme</a>

Here is the above link in action:  Download Meme

This approach is very straightforward and has the potential to save time and headaches for developers moving forward. Support for IE and Safari is still missing, but since the the target file is referenced in the href of the link, if a browser is missing support for the download attribute, it will attempt request the file like any other link.