Build Offline Ionic Angular 5 Applications
Tags: hybridappdevelopment, angular, ionic, cordovaplugin
Published: 2022-06-29 06:18:18

---
title: Build Offline Ionic Angular 5 Applications
published: true
date: 2022-06-29 02:52:55 UTC
tags: hybridappdevelopment,angular,ionic,cordovaplugin
canonical_url: https://enappd.com/blog/build-offline-ionic-angular-apps/192/
---

![](https://cdn-images-1.medium.com/max/1024/1*aGE2hUVcPYAouCiXb6YfLg.png)

In mobile apps, we have come across many conditions in which, the rendered data (from the server) is the same most of the time but is repeatedly fetched from the server. This data fetching every time from the server is useless and a huge waste of data bandwidth. Another similar situation where we can’t even access the app is — when we call the sever with no network/internet then there will be NO\_INTERNET error in the App.

In such situations, we can customize the Ionic App, and manage the application when there is no internet. To do that we have to first recognize the status of the Network/Internet connection, and then perform online or offline logic.

### Why do you need offline Performance?

Why do we need offline application performance ?? .. The Answer is to improve the user experience and maintain the state of the application properly, even with network fluctuations. As in today’s world, everything is dependent on the Internet and most applications won’t work if there is no Internet available. In some cases, it can, while in other cases we strictly need the Internet to perform some action. So the complete offline performance is dependent on your business logic. e.g If you have an online text editor it can let you type and edit after the initial loading of the document without any internet, but, for saving and other syncing features it will require internet.

### Any drawbacks of Offline Performance?

With many advantages, offline performance brings many challenges for the developers. As this brings unexpected things to happen like no proper syncing of offline database and online database, it will lead the application to the dead state. And one of the major points, User is unpredictable and can take any action — such an unhandled case can cause an inconsistent app state, so keep in mind while giving offline privileges to the user.

### How do Ionic 5 Applications works offline?

We will modify our Ionic application to have two major features, required for offline functionality:-

1. **Store the DB tables on the device's local storage** :- We will store some of the users and necessary information in the local storage (LocalStorage API, or any browser database). It will help us to operate the application offline as we have that data stored in local storage. This will resolve some of the problems that are less dependent on the Server. If your application has a very small database, you can sync all data of the user to phone storage. However, if you have large data of individual users, you can store data only for that session. This logic can be different for different apps, and one has to design the business logic accordingly.
2. **Store API calls in local storage** :- With data, we also store the APIs in local storage, we store APIs in such a way that it helps us recognize which API is completely served (i.e. response is received) and which one is left to be served. This helps us to make application flow more stable, as if there is no network available and we want to perform an HTTP POST request to our server then we store the API request in the local storage and will perform it later as soon as the network is available. e.g. Like syncing documents with an online database.

### Implementing the Offline features in Ionic App :

We will assume that you are already familiar with simple Ionic Angular apps, if not — do check our other blogs to learn about its setup. We will start with an already set up Ionic Angular application — and ionic commands will be used directly in the project root directory.

#### Network detection plugin

The below command will install the packages and library required for network detection in the working Ionic project.

```
$ ionic cordova plugin add cordova-plugin-network-information
$ npm install @ionic-native/network
```

Using this command we will detect whether we have the network connection or not.

#### **Maintaining user data in the local storage table**

Maintaining users' tables in local storage can give an illusion to the application - that the app is working in offline mode. So while login/registering, we will save the user's data in local storage and use that user's data everywhere we need in the application. Be sure not to store secure data like ca_rds_ and _passwords_ in the offline database.

Before that, we have to install the **cordova-sqlite-storage** plugin & **@ionic/storage** in our project.

```
$ ionic cordova plugin add cordova-sqlite-storage
$ npm install --save @ionic/storage
```

The above command will install the storage plugin and package in the working project and now we have to Import _[Line 14, Line 19]_ and Inject the SQLite and N/W information module _[Line 31, Line 39]_ in **app.module.ts**

{% gist https://gist.github.com/vaibhavgehani/e2b089776c78f4af6101c96bf97b4224 %}

In **app.module.ts** , we have declared an **APP\_INITIALIZER** which basically runs the **_load_()** function (shown below in code) defined in the **InitUserProvider** service file, during the initial load of the application (Before loading any components). This **_load_()** function will check if there is an existing user in the local storage (if any then set it as the **_loggedInUser_** ). It will be dependent on network status, if the network exists — then the User will be fetched from the server. And if there is no network, then localUser will be saved as **loggedInUser**.

```
async load() {
  if (this.networkStatus) {
    const onlineUser = await this.api.getUserFromServer(this.userid)
    this.api.setLoggedInUser(onlineUser)
  }
  else {
    const localUser = await this.data.getStoredUserData();
    this.api.setLoggedInUser(localUser);
  }
}
```

And during registering or login flow we can set the user in the local storage using the **_setUserData_** _()_ function defined in **DataService** file **(create data service file using the ionic generate service \*path/filename\*)**. You can add the below line in your existing login/register logic.

```
await this.data.setUserData(userData);
```

In the above line, **_userData_** is the user's data fetched from the server or any database. You must be wondering that we are fetching the data from the server then why is offline data saved here? Only at first login, we have to fetch the data from the server after that we simply use the local storage data, every time.

{% gist https://gist.github.com/vaibhavgehani/cf51424d7b10e1ef95f53c479fd0cf07 %}

Here in **DataService** , we use the **set** and **get** methods of the storage module. This will store the data in **key: value** pairs in the local storage. We are done with storing the data and now we can get the Data when the app is offline. To check whether the app is offline or online, we will use the Network module. Below is the code for **_load_** () function that will run when the app is initialized:-

{% gist https://gist.github.com/vaibhavgehani/27a7c49a6602490deddfc1fa2ccb1639 %}

Here we first set the Network listener using **checkInternetConnection method** _[Line 16]_ that will detect whether we have the network or not and on the basis of that we fetch the user's data from the server or from the local storage.

You can modify the above code according to your app structure, as this code will help you to work offline with the user table.

#### Maintaining API Storage database

In this section, we will explore how can we store the API calls in the local storage. We will define a procedure that will help our application to work in an offline manner, this procedure will help us to save the API data(if there is no network/internet) and call it later when the network is available. Overall we have 2 flows:-

1. **The Application does not have the network/Internet:-** In this flow, we will save the HTTP request(API — path and data) in the local storage and then make the HTTP request when network/Internet is available. And once the HTTP request is served, then we will set a **completed** flag to true. This procedure will help us to store the API and later call that when the network is available.

2. **Application has the Network/Internet:-** This will be the normal flow in which we have the network/internet. We first save the HTTP request(API) in local storage and make the HTTP request and make its completed flag to true. Remember we always store the HTTP request in local storage anyway, network is available or not, this makes flow easier to code.

![](https://cdn-images-1.medium.com/max/1024/1*0mQGXI7WWw7mfrA9w8OCXw.png)


In the above 2 flows, the initial steps are the same but further, they are divided into 2 parts that will be decided on the basis of the availability of the network. We will implement this logic in a separate service file i.e. **API-manage** r (to create the service file run the below command)

```
$ ionic generate service services/api-manager
```

Once the above command is executed the service file will be added to the project, Now we can start to code our main logic:-

![](https://cdn-images-1.medium.com/max/490/1*ZeYBlVyHQw9trIm4pwomGA.gif)

Below is the code for the API-Manager (we will explain it later):-

{% gist https://gist.github.com/vaibhavgehani/9d037f3cb216bf25e4c4180ce3cad8d4 %}

In the above code, we store and make the HTTP request using the **_storeCallAndRespond()_** function _[Line 96]_. In this function, we simply store the API Request in a particular format mentioned below:-

```
_const_ action: StoredRequest = {
  url: url,
  type: method,
  data: data ? data : null,
  time: new Date().getTime(),
  completed: false,
  response: null,
  header: header,
  id: Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5)
};
```

This Action object contains the parameters that will be used in making HTTP requests like _URL_, _method_(type), _completed_ flag, _response_ (set the response when an HTTP request is served), _headers_, and the _unique Id_.

Now we can set the API request using **_storeRequest_** () method that is defined in API-manager itself :-

```
storeRequest(_action_) {
  this.storage.get(environment.REQ_STORAGE_KEY).
  then((_storedOperation_) _=>_ {
    _let_ storedObj = JSON.parse(storedOperations);
   if (storedObj) {
    storedObj.push(action);
   } else {
    storedObj = [action];
 }
return this.storage.set(environment.REQ_STORAGE_KEY, JSON.stringify(storedObj));
});
}
```

The above code will push the existing API request object (action) into the local storage DB. Till this point above two points have the same flow. Now onwards on the bases of network/internet availability, we will differentiate between the flow:- **(further logic is contained inside the _repeatRequest_() method)**

```
async repeatRequest(_action_) {
  return new Promise(async (_resolve_, _reject_) _=>_ {
    _let_ response;
    if (!this.networkStatus) { <-- No Internet
    // No Internet
      resolve(action.data);
    } else { <-- Internet is working
    // Internet is there
      if (action.type === 'GET') {
        response = await this.http.request(action.type, action.url,
        {headers: action.header}).toPromise();
      } else {
        response = await this.http.request(
        action.type,
        action.url,
       {body: action.data, headers: action.header}
        ).toPromise();}
      this.updateActionObject(action, response);
      resolve(response);
     }
});
}
```

In this flow, we will first check whether the network/internet is available or not _[denoted in the above code using ←]_, and if we have the network — we will make the HTTP request using the **action** object and make that API stored Object’s( **action** ) **completed** flag _true_ and save the response in it.

And if the app doesn’t have the network then we will simply resolve the promise and continue the UI flow, This procedure will make no change in UI rendering and the end-user will not feel like there is no internet/network. After this, once the network is back the flow will call the **_checkForUnCompleteAPI_** () method _[Line 1 in below Code]_ that will serve the uncalled(i.e. completed: false) HTTP request.

{% gist https://gist.github.com/vaibhavgehani/77532496984cb1883b71ffdfcde2a961 %}

The above code will check for the API request array in local storage and if any, then passes it to the **_sendRequests_** () method that will make the uncompleted HTTP request using the **action**  object:-

```
sendRequests(_operations_: StoredRequest[]) {

_let_ obs = [];
_let_ oneObs;
for (_let_ op of operations) {
  if (!op.completed) {
  if (op.type === 'GET') {
   oneObs = this.http.request(op.type, op.url, {headers: op.header});
  } else {
   oneObs = this.http.request(op.type, op.url, {body: op.data, headers:
op.header});
  }
  _console_.log('Array res', oneObs);
  obs.push(oneObs);
 }
}
return forkJoin(obs);
}
```

The above code will check for the **completed** flag for each API request, and if the **completed** flag is _false_ then make an HTTP request using the stored action object.

This above-defined code (i.e. API-manager service) will be helpful when our UI is dependent on the API call but we do not have the network, then we store the API call in local storage with all its parameter and once the internet comes back then we try to make that HTTP request at that time.

### How to modify HTTP requests in the existing App?

Now we will look at how we add this HTTP API logic to the existing application which earlier has direct API calls:-

Where you have API calls (i.e. HTTP calls) in your application, there instead of directly making that HTTP call we will pass the required parameters to the **_storeCallAndRespond()_** function like below:-

```
updateUser(_id_, _userData_): Promise <_any_> {
return new Promise(async (_resolve_, _reject_) _=>_ {
  _const_ response = await
  this.apiManager.storeCallAndRespond('PUT', ` `${this.url}/clients/${id}`, { Authorization: `JWT ${this.token}` }, userData);
  resolve(response);
 });
}
```

We will pass the required HTTP options to the **_storeCallAndRespond_** () method _[Below Code]_ defined under API-manager. There are 3 arguments that are passed to **_storeCallAndRespond()_** method :- 1) Request Method. 2) Request URL. 3) Request Header

```
storeCallAndRespond(method, url, header, data?): Promise <any> {
  return new Promise(async (resolve, reject) => {
    const action: StoredRequest = {
        url: url,
        type: method,
        data: data ? data : null,
        time: new Date().getTime(),
        completed: false,
        response: null,
        header: header,
        id: Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5)
    };
   const Store = await this.storeRequest(action);
   this.repeatRequest(action).then((response) => {
    console.log('Response', response);
    resolve(response);
   })
 });
}
```

### Conclusion

In this tutorial, we have learned how we can covert our Ionic 5 application into an offline working application. So now you are ready to fit this feature in your existing or new application with ease. If you want to know more about different features and methods to handle any of the technology, just go to [**Enappd Blogs Section**](https://enappd.com/blog/).

### Next Steps

If you liked this blog, you will also find the following Ionic blogs interesting and helpful. Feel free to ask any questions in the comment section

- Ionic Payment Gateways — [Stripe](https://enappd.com/blog/ionic-4-stripe-payment-integration-with-firebase-for-apps-and-pwa/17) | [PayPal](https://enappd.com/blog/ionic-4-paypal-payment-integration-for-apps-and-pwa/16) | [Apple Pay](https://enappd.com/blog/how-to-integrate-apple-pay-in-ionic-4-apps/21) | [RazorPay](https://enappd.com/blog/how-to-integrate-razorpay-in-ionic-4-apps-and-pwa/20)
- Ionic Charts with — [Google Charts](https://enappd.com/blog/ionic-4-charts-using-google-charts/66)| [HighCharts](https://enappd.com/blog/adding-charts-in-ionic-4-apps-and-pwa-part-3/60) | [d3.js](https://enappd.com/blog/adding-charts-in-ionic-4-apps-and-pwa-part-2/54) | [Chart.js](https://enappd.com/blog/charts-in-ionic-4-apps-and-pwa-part-1/52)
- Ionic Social Logins — [Facebook](https://enappd.com/blog/facebook-login-in-ionic-4-apps-using-firebase/25) | [Google](https://enappd.com/blog/google-login-in-ionic-4-apps-using-firebase/39) | [Twitter](https://enappd.com/blog/twitter-login-in-ionic-4-apps-using-firebase/24)
- Ionic Authentications — [Via Email](https://enappd.com/blog/email-authentication-with-firebase-in-ionic-4/38) | [Anonymous](https://enappd.com/blog/firebase-anonymous-login-in-ionic-4/37)
- Ionic Features — [Geolocation](https://enappd.com/blog/using-geolocation-geocoding-and-reverse-geocoding-in-ionic-4/45) | [QR Code reader](https://enappd.com/blog/qr-code-scanning-and-optical-character-recognition-ocr-in-ionic-4/9)| [Pedometer](https://enappd.com/blog/best-fitness-plugins-for-ionic-4-how-to-use-pedometer/15)
- Media in Ionic — [Audio](https://enappd.com/blog/spotify-like-music-in-ionic-4-apps/48) | [Video](https://enappd.com/blog/adding-video-player-in-ionic-4-app/64) | [Image Picker](https://enappd.com/blog/image-picker-in-ionic-4-app/67) | [Image Cropper](https://enappd.com/blog/how-to-add-image-cropper-in-ionic-4-app/68)
- Ionic Essentials — [Native Storage](https://enappd.com/blog/ionic-4-save-and-retrieve-data-locally-on-device/59) | [Translations](https://enappd.com/blog/how-to-translate-in-ionic-4-globalization-internationalization-and-localization/11) | [RTL](https://enappd.com/blog/rtl-right-to-left-use-in-ionic-4/50)
- Ionic messaging — [Firebase Push](https://enappd.com/blog/implement-ionic-4-firebase-push/34) | [Reading SMS](https://enappd.com/blog/automatically-read-sms-in-ionic-4-apps/42)
- Ionic with Firebase — [Basics](https://enappd.com/blog/how-to-integrate-firebase-in-ionic-4-apps/23) | [Hosting and DB](https://enappd.com/blog/firebase-with-ionic-4-hosting-auth-and-db-connection/58) | [Cloud functions](https://enappd.com/blog/firebase-cloud-functions-in-ionic-4-complete-guide/32)

### Ionic React Full App with Capacitor

If you need a base to start your next Ionic 5 React Capacitor app, you can make your next awesome app using [Ionic 5 React Full App in Capacitor](https://store.enappd.com/product/ionic-react-full-app-capacitor/)

![Ionic 5 React Full App in Capacitor from Enappd](https://cdn-images-1.medium.com/max/760/1*G3yOFVX4oABx9MhUy-3kng.png)

### Ionic Capacitor Full App (Angular)

If you need a base to start your next Angular **Capacitor app** , you can make your next awesome app using [Capacitor Full App](https://store.enappd.com/product/capacitor-full-app-with-ionic-angular/)

![Capacitor Full App with huge number of layouts and features](https://cdn-images-1.medium.com/max/736/0*UwSHcofTMStMnzAX.png)


### Ionic Full App (Angular and Cordova)

If you need a base to start your next Ionic 5 app, you can make your next awesome app using [Ionic 5 Full App](https://store.enappd.com/product/ionic-full-app)

![Ionic Full App with huge number of layouts and features](https://cdn-images-1.medium.com/max/700/0*1ArpKyhiDHZnevwB.jpeg)


* * *