August 11, 2016
  • All
  • Framework
  • Ionic
  • Ionic 2
  • Tutorials

Building an Ionic App with Offline Support, Part 1

Drew Rygh

Special thanks to Ionic’s Justin Willis for updating this repo and post on November 4, 2016.

Service workers, app shell, progressive web apps—anything involving offline support seems to be all the rage these days. Whether it’s a new design concept or a shiny new browser feature, developers seem to have many options when it comes to adding better offline support to their apps. All of these options can be overwhelming, but it doesn’t need to be that way.

Start with the Basics

While service workers and the app shell design concept are great, sometimes it’s best to start with the basics. SQLite is a mature database that has been around for ages. Ionic has a great native plugin for it, which happens to work great on iOS, Android, and Windows Phone.

In this series, we’ll be building a weather app that is fully functional while offline. This post will walk through the steps of setting up the app and adding SQLite, so it can display data while offline. The app will pull seven days of weather data from a service and store it locally for later use. If a user opens the app without an internet connection, the app can fall back to use data collected up to seven days ago. Here’s what the final product will look like:

weather app

Getting Started

The code for this weather app can be found here. We will be working from the part-1 branch, which contains a number of steps that are commented out. You can follow along by uncommenting the code in each step of this blog post. Let’s begin by cloning the repo and installing its dependencies:

$ git clone https://github.com/jgw96/ionic-offline-demo.git
$ cd ionic-offline-demo && git checkout part-1
$ npm install

We’ll also need to add Ionic’s SQLite and Geolocation plugins:

$ ionic plugin add cordova-sqlite-storage
$ ionic plugin add cordova-plugin-geolocation

Finally, if you’re planning on running the demo locally, you’ll need to sign up and obtain API keys for forecast.io and Google Maps. We’ll be using these services to get weather data and translate our geolocation into friendly city and state names.

Using SqlStorage

We’ll be using SQLite Ionic Native module, a wrapper Ionic provides that makes it easier to interact with a SQLite database. Let’s open up home.ts and import it:

// [Step 1 - Using SQLite]
Import { SQLite } from ‘ionic-native’;

Creating Tables

Next, we need to create a table to store the forecast data we’ll be saving later. Each row in this table will represent data for a particular day. When our app is initialized, or in the constructor method for our page, let’s add the following query to create the table:

    // [Step 2 - Creating Tables]
    this.storage = new SQLite();
    this.storage.openDatabase({
      name: ‘ionic.offline’,
      location: ‘default’
    }).then(() => {
      this.storage.executeSql(`create table if not exists forecasts(
        date CHAR(5) PRIMARY KEY,
        location CHAR(40),
        icon CHAR(30),
        tempCurrent INT,
        tempMin INT,
        tempMax INT
      ))`, {});
    });
   ```


### Saving Data
Now that our table is created, let’s write a function that will save forecast data. We will pass this function a `forecasts` object, which contains data obtained through the [forecast.io API](https://forecast.io/):


```ts
  // [Step 3 - Saving Data]
  saveForecasts = (forecasts) => {
    let query = "INSERT OR REPLACE INTO forecasts VALUES (?, ?, ?, ?, ?, ?)";
    for (let forecast of forecasts) {
      this.storage.executeSql(query, { forecast.date,
                                 forecast.location,
                                 forecast.icon,
                                 forecast.tempCurrent,
                                 forecast.tempMin,
                                 forecast.tempMax });
    }
    return forecasts;
  }


Retrieving Data

Our weather app needs to be able to retrieve the forecast for the current day. The following function will return forecast data for the given date:

  // [Step 4 - Retrieving Data]
  getForecast(date: string) {
    return this.storage.executeSql("SELECT * FROM forecasts WHERE date = ?", { date }).then((resp) => {
      if (resp.res.rows.length > 0) {
        for (var i = 0; i < resp.res.rows.length; i++) {
          let item = resp.res.rows.item(i);
          return item;
        }
      }
    });
  }

Tying it Together

When the app is initialized, we now have the option to use data stored locally. If we can’t retrieve local data, we can go to the network to retrieve the data. Let’s check out what this looks like in code:

    // [Step 5 - Tying it Together]
    this.getForecast(this.getToday()).then((data) => {
      if (data) {
        // obtained forecast from database
        this.data = data;
      } else {
        // could not get forecast from database, go to network
        this.fetchForecasts();
      }
    });

With this added, our app will be able to display today’s forecast while offline, assuming the forecast was saved earlier. Check out the GitHub repo for all of the code used to build this app.

Not Just About Offline Support

By retrieving data from a local SQLite database, rather than going to the network, we’re improving the experience for all of our users, not just the ones using our app offline. Network requests are expensive, and by preventing them, our content gets displayed more quickly. Utilizing local storage is not just about offline support; it’s about performance.

Conclusion

Adding offline support to an existing app can be straightforward when you start with the basics. By utilizing the Ionic Native SQLite module, we not only add better offline support to our apps, we improve their performance.

At this point, you may be wondering what happens when we can’t retrieve data from the database or from the network. In the next post, we’ll address this by adding a No Connection page that gives the user an option to open their network settings.

Check out the code on GitHub, and let us know how it goes!


Drew Rygh