Adding Offline Support to Your Kendo UI Mobile App

Kendo UI’s third, and final, release of 2014 has just landed. For Kendo UI Mobile users there’s some awesome stuff—like improved AngularJS support and a new material design theme — but what I’m excited about, and what I’m writing about today, is the new offline support built into Kendo UI.

Personally, offline support is one of those features I always feel like I should add to my apps but never actually get around to, largely because it’s hard, and I’m lazy. But luckily for me the new offline support in Kendo UI makes this functionality trivial to add. Let’s see how it works.

Data in Kendo UI Mobile

To understand how offline storage works in Kendo UI Mobile you have to know a little about how Kendo UI DataSources work. Let’s look at an example.

Suppose you want to build a grocery list app around a JSON endpoint at http://api.myapp.com/Groceries. Sending GET requests to that endpoint will return a list of groceries, and sending POST requests will add new groceries. A Kendo UI DataSource to connect to such an endpoint would look something like this:

var groceryDataSource = new kendo.data.DataSource({
    transport: {
        read: {
            url: "http://api.myapp.com/Groceries",
            dataType: "json"
        },
        create: {
            url: "http://api.myapp.com/Groceries",
            dataType: "json"
        }
    }
});

I’m keeping the setup super simple for this article, but the Kendo UI DataSource contains a plethora of options to make connecting to a huge variety of services possible. Want to configure how deletes are handled? Use the transport.destroy option. Need to massage the data from your legacy CMS to work in your mobile app? You can use the schema option for that. You can peruse the DataSource API docs and getting starting documentation to get an idea of what’s possible.

Tying data to widgets

So now that you have a DataSource how to you use it? In Kendo UI Mobile it’s as easy as setting the dataSource option on any widget that supports DataSource binding. For example, assuming the above DataSource is available at window.groceryDataSource, you can build a ListView widget that uses this DataSource with the code below:

<ul data-role="listview" data-source="groceryDataSource" data-template="grocery-template"></ul>
<script id="grocery-template" type="text/html">
    #: Name #
</script>

A couple things need a brief explanation here. First, note that the data-template attribute on the ListView matches the id attribute of the <script> tag. This tells the ListView widget how to render each item in the DataSource. The code above assumes that each grocery object that comes from the backend service has a Name property. The ListView widget takes care of building <li> elements and appending them to the list automatically. For instance, if a GET to http://api.myapp.com/Groceries returned [{"Name": "Grapes"},{"Name":"Bread"}], the above ListView would contain <li>Grapes</li><li>Bread</li>.

Concerned about exposing the DataSource object on the global scope? No worries. Kendo UI has a full MVVM framework that can act as a scoping mechanism, and keep references out of the global scope. A deep dive into the Kendo UI MVVM functionality is out of the scope of this article, but you can learn more about it on our docs.

What’s great about the Kendo UI DataSource is it completely abstracts your view logic from the underlying data services. Kendo UI will automatically perform a GET request when this ListView widget needs data. When you need to add items to the DataSource you can use its add() method. Kendo UI automatically updates the view of any widgets bound to that DataSource. Cool, huh? When rendered the above ListView widget look a little something like this:

e60JdJH

Like the look of this app? It’s using one of the new Kendo UI flat themes from http://kendoflatthemes.com/.

Adding offline functionality

So where does offline play into this? Assuming our same DataSource is still available at groceryDataSource, you can use the following two lines to add a new item to the list:

groceryDataSource.add({ Name: "Cheese" });
groceryDataSource.sync();

The add() method updates the DataSource and re-renders widgets; the sync() method sends the appropriate requests to the backend. (There’s also an autoSync option that removes the need for the explicit call to sync().)

This works great, except for one problem: the app relies on network connectivity, and will silently fail when the user is offline. If a user adds an item in a tunnel it’ll just disappear. Surprise! Luckily, the new offline functionality in Kendo UI makes this pretty easy to work as the user would expect. In fact, it’s just two steps.

Step 1: Use the offlineStorage option

The first step is to specify the offlineStorage option on the DataSource object. For example the code below adds the option to our grocery DataSource.

var groceryDataSource = new kendo.data.DataSource({
    offlineStorage: "grocery-list",
    transport: {
        ...
    }
});

Kendo UI uses the HTML5 localStorage API to store data offline by default, and the offlineStorage option is used as the key. So after adding the option to the code above, you could run localStorage.get("grocery-list") to get the raw data stored in the DataSource.

Local storage is limited to 5MB of data per app, so for apps with large amount of data you may need to seek alternative storage options. The Kendo UI DataSource makes it easy to plugin alternative methods into its APIs. Check out the object version of the offlineStorage option for examples. For more information on data quotas and working around them across browsers, check out this excellent article on the topic from HTML5 Rocks.

Step 2: Call the online() method appropriately

Kendo UI does not detect online/offline access for you automatically, because doing so can be tricky, and how you want to handle that depends on what you’re building. Things are relatively sane for Cordova apps, as the Cordova network information plugin detects information about the device’s connectivity using the device’s native APIs. One thing the network connectivity API does is fire online and offline events when the device goes online and offline, respectively. Therefore implementing offline functionality in our groceryDataSource is as easy as adding the following code:

document.addEventListener("online", function() {
    groceryDataSource.online(true);
});
document.addEventListener("offline", function() {
    groceryDataSource.online(false);
});

For those curious, the network information plugin is installed by default in new Telerik AppBuilder projects. The AppBuilder simulators also provide a handy way to simulate online and offline conditions. It’s worth checking out if you haven’t already.

Here’s how this code works. When the user goes offline, the offline event handler runs, calling online(false) on the DataSource. This puts the DataSource in offline mode, and it starts maintaining an internal __state__ field on each data item in the DataSource, which gets set to either "create", "update", or "destroy".

When the user comes back online, the online event handler runs, calling online(true) on the DataSource. This tells the DataSource to send all requests necessary to synchronize modified data with the backend. All of this is completely transparent and not something you have to keep track of yourself, which I think is super cool.

Things are a little trickier when it comes to traditional web apps. Although there are standardized online and offline events, how they work is not consistent across browser implementations. For example, some browsers consider you “online” if you’re connected to a network, regardless of whether that network is connected to the internet. For those interested in adding offline storage to a traditional web app, I’d recommend reading through Kendo UI’s documentation on the issue. It walks through a few different approaches that you may want to use based on your requirements. Believe it or not, periodically polling a server is the most bulletproof method of accurately detecting connectivity.

Wrapping Up

Offline storage is an important consideration for any mobile app. Kendo UI Mobile has a fairly slick implementation that makes it quite simple to make offline storage possible. Because the offline ability is implemented at the DataSource level, it’s something you can use with any Kendo UI widget that binds to DataSources—including grids, schedulers, the new treelist widget, and more.

If you want to learn more about what’s new in Kendo UI’s Q3 release, check out our keynote video. It walks through the new features, including this implementation of the offline functionality. Kendo UI Mobile and the Kendo UI DataSource are part of the open source Kendo UI Core project, which you can download and use for free at https://github.com/telerik/kendo-ui-core.

Header image courtesy of photosteve101

Comments