Building an Ionic App with Offline Support, Part 2
Special thanks to Ionic’s Justin Willis for updating this repo and post on November 4, 2016.
In the previous post, we added basic offline support to a weather app by storing data locally with the Ionic Native SQLite plugin. However, even this can fail. There are times where we may not be able to retrieve data from the database or from the network. In this post, we’ll be solving this problem by creating a friendly alert that gives the user the option to open their network settings.
Here’s what it will look like:
This will be created by combining the alert component with the Ionic Native Diagnostic plugin. We will also be creating a reusable service that wraps Angular’s HTTP module. This service will display our alert whenever an HTTP request is made and there is no internet connection available. Let’s get started!
Creating the Alert
To get started, add the the diagnostic plugin, as well as the network plugin:
$ ionic plugin add cordova.plugins.diagnostic
$ ionic plugin add cordova-plugin-network-information
Next, create a new service and import the plugins we just added, along with a few Ionic and Angular modules we need:
import {Injectable} from 'angular2/core';
import {Alert, NavController} from 'ionic-angular';
import {Network, Connection} from 'ionic-native';
@Injectable()
export class NetworkService {
constructor(public nav: NavController) {
}
}
The Injectable
decorator will allow this service to be used by the HTTP service we’re going to create in the next section. Now that the service is defined, a few convenience methods can be added to it:
noConnection() {
return (Network.connection === 'none');
}
private showSettings() {
if (cordova.plugins.diagnostic.switchToWifiSettings) {
cordova.plugins.diagnostic.switchToWifiSettings();
} else {
cordova.plugins.diagnostic.switchToSettings();
}
}
Both of these functions use one of the Ionic Native plugins we added earlier. The noConnection
function determines whether there is a valid internet connection available, and the showSettings
function opens the phone’s settings. Now that these are added, let’s use them in a third method:
showNetworkAlert() {
let networkAlert = Alert.create({
title: 'No Internet Connection',
message: 'Please check your internet connection.',
buttons: [
{
text: 'Cancel',
handler: () => {}
},
{
text: 'Open Settings',
handler: () => {
networkAlert.dismiss().then(() => {
this.showSettings();
})
}
}
]
});
networkAlert.present();
}
This simply creates a new alert with a handler that calls our showSettings
function. With these three methods, our NetworkService
class is complete and ready to be used.
Creating the HTTP Wrapper
It’s possible to use NetworkService
each time our app makes a network request; however, this would be quite tedious. Instead, let’s create a new service that wraps Angular’s HTTP module. Notice that we are importing a few modules from Angular and inject both the HTTP module and our NetworkService
into the new service:
import {Http, Request, Response, RequestOptionsArgs} from 'angular2/http';
@Injectable()
export class SafeHttp {
constructor(private http: Http, private networkService: NetworkService) {
}
}
Next, copy the RESTful actions we want to use with our service and add some logic to them, so that they use the methods we added to NetworkService
:
get(url: string, options?: RequestOptionsArgs) {
if (this.networkService.noConnection()) {
this.networkService.showNetworkAlert();
} else { return this.http.get(url, options) }
}
post(url: string, body: string, options?: RequestOptionsArgs) {
if (this.networkService.noConnection()) {
this.networkService.showNetworkAlert();
} else { return this.http.post(url, body, options) }
}
...
This will show our alert only when there is no connection available, and will otherwise pass the request to the HTTP module. We can repeat this pattern for the other RESTful actions.
Now, let’s use this service in our app!
Using our HTTP Wrapper
First we need to add our services to our ngModule
:
import { SafeHttp, NetworkService } from './safe-http';
@NgModule({
…
…
…
Providers: [SafeHttp, NetworkService]
})
Then to use our HTTP wrapper service, import it into our page:
import { Page } from 'ionic-angular';
import { SafeHttp, NetworkService } from './safe-http';
@Page({
templateUrl: 'my-page.html',
})
export class MyPage {
constructor(public safeHttp: SafeHttp) {
}
}
Now, we can use it just as we would the regular HTTP module:
makeNetworkRequest() {
this.safeHttp.get('http://localhost:8100')
}
Conclusion
Certain parts of our apps may always require an internet connection, but it’s not safe to assume that the user will always have one. Part of crafting a great UX involves handling cases in which things go wrong in an elegant way. By combining the alert component with the Ionic Native Diagnostic to present a friendly message, we can do just that.
Check out the code on GitHub and let us know how it goes!