Ionic Storage Module: Ionic 2

This video tutorial is an update to our previous tutorial Ionic Storage: Ionic 2.

Major Changes To Note
Previously we use to import Storage class inside src/app/app.module.ts file and we would list it as one of the providers. But now we need to import IonicStorageModule class inside src/app/app.module.ts file and list it inside imports array. That’s the only difference in implementing Ionic Storage, everything else is as described in Ionic Storage: Ionic 2 video tutorial.

Database

In this video tutorial only concentrate on src/app/app.module.ts file and for implementing storage set and get method refer Ionic Storage: Ionic 2 video tutorial itself.

Ionic Storage Module In Ionic 2 (Update)



YouTube Link: https://www.youtube.com/watch?v=lKsspk5kafE [Watch the Video In Full Screen.]



src/app/app.module.ts

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
 
import { IonicStorageModule } from '@ionic/storage';
 
@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    IonicModule.forRoot(MyApp),
    IonicStorageModule.forRoot()
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

Here we import IonicStorageModule class and list it inside imports array. We can also specify database name and database preference as follows:

imports: [
    IonicModule.forRoot(MyApp),
    IonicStorageModule.forRoot({
      name: '__mydbName',
      driverOrder: ['sqlite', 'indexeddb', 'websql']
    })
  ]

Now implementing get and set methods wherever we need it. Practically it would be useful inside a data provider file, but in this tutorial am implementing inside a normal page, so that I keep the complexities out for this basic lesson.

src/pages/home/home.ts

import { Component } from '@angular/core';
 
import { NavController } from 'ionic-angular';
 
import { Storage } from '@ionic/storage';
 
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
 
  constructor(public storage: Storage, public navCtrl: NavController) {
    this.storage.ready().then(() => {
     this.storage.set('myKey', 10);
    });
  };
 
  getValues(){
     this.storage.get('myKey').then((data) => {
       if(data != null)
       {
         console.log(data);
       }
     });
  };

Here we import Storage class and create an instance of it. We check if the storage is ready. Once its ready it returns/resolves a promise. So now we can set value using this.storage.set() method. We can set an object, an array or a strong value or simply a number.

We can get the value by using its get method, which returns the value stored in the key as promise. If nothing is stored in the key, it returns null.

Using Ionic Native: Ionic 2

Today lets learn about an important project which helps us use 130+ native mobile SDK features in our Ionic application through simple JavaScript interfaces – Ionic Native.

ionic native ionic2

Ionic Native is a TypeScript wrapper for Cordova/PhoneGap plugins that make adding any native functionality you need to your Ionic 2 mobile app easy. Ionic Native wraps plugin callbacks in a Promise or an Observable, providing a common interface for all plugins and ensuring that native events trigger change detection in Angular 2.

Related Read:
Ionic 2 Starter Templates.
Adding AdMob In Ionic 2.

Using ‘Ionic Native’ In Ionic 2 Applications



YouTube Link: https://www.youtube.com/watch?v=SM54loG63ks [Watch the Video In Full Screen.]



There are two steps required to use Ionic Native in our project
1. Install the Ionic Native package for each plugin you want to add.
2. Install the plugin using Cordova or Ionic CLI.

For example:
If we want to add AdMob plugin to our application:
Step 1: Add/ Install Specific Ionic Native package

npm install --save @ionic-native/ad-mob

Step 2: Add / install the plugin using Cordova or Ionic CLI.

ionic plugin add cordova-plugin-admobpro

Additional Implementation
Listing Plugin Class as Provider: src/app/app.module.ts

import { AdMob } from '@ionic-native/ad-mob';
import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
 
 
 
@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    AdMob,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

Look at the first import statement in above code snippet. We import AdMob plugin and the way we import is specific to ad-mob and we do not import the whole ionic native script here – thus saving application load time.

Also specify the class name as provider. Because we use the services provided by this class in our application.

Working of plugin: src/app/app.component.ts

import { AdMob } from '@ionic-native/ad-mob';
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
 
import { HomePage } from '../pages/home/home';
 
@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = HomePage;
 
  constructor(public admob: AdMob, platform: Platform) {
    platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
 
      this.admob.createBanner({
        adId: 'ca-app-pub-5732334124058455/4262868443',
        isTesting: false,
        autoShow: false
      }).then(() => {
        this.admob.showBanner(8);
      });
 
    });
  }
}

Again, we import AdMob native code wherever we want to implement the service of this plugin. We create instance of the class we want to implement – as constructor argument. Then inside platform.ready() method we call the methods of these classes and implement its services inside our project.

Trouble Shoot
1. If you’re getting ‘plugin not found‘ error. OR Cannot find module “@ionic-native/ “ errors, then follow below commands to fix it.

npm rebuild
npm install

2. Error Message “Provider Not Found:
Make sure to include all the specific packages inside src/app/app.module.ts file and list its class name inside providers array.

ngClass Directive: Ionic 2

Today lets learn how to make use of ngClass angular directive in our Ionic 2 application.

Related Read:
ngIf, index, first, last: Ionic 2

ngClass Directive: Ionic 2



YouTube Link: https://www.youtube.com/watch?v=r1ZRoXBcUfs [Watch the Video In Full Screen.]



Company Names: src/pages/home/home.ts

import { Component } from '@angular/core';
 
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
items: any = [];
  constructor() {
    this.items = [
      'Microsoft',
      'Apple',
      'Oracle',
      'Google',
      'IBM',
      'Tesla',
      'Technotip'
    ];
  }
}

We have an array of company names which is being assigned to variable items.

ngClass angular directive ionic 2

Output
Microsoft
Apple
Oracle
Google
IBM
Tesla
Technotip

CSS Class: src/pages/home/home.scss

page-home {
    .bold{
        font-weight: bolder;
    }
    .normal{
        font-weight: normal;
    }
}

We define two CSS classes which we use to apply for alternate list items – using ngClass directive. Alternatively the list items appear in bold and in normal font weight.

ngClass Directive – using ternary operator: src/pages/home/home.html

< ion-header>
  < ion-navbar>
    < ion-title>
      Company Names
    < /ion-title>
  < /ion-navbar>
< /ion-header>
 
< ion-content padding>
< ion-list no-lines>
  < ion-item *ngFor="let item of items; let i = index;"
             [ngClass]="(i % 2 == 0) ? 'bold' : 'normal'">
    {{i+1}}. {{item}}
  < /ion-item>
< /ion-list>
< /ion-content>

Here we use ternary operator and whenever i % 2 is zero we apply bold class to that item, if not we apply normal class to that list item.

ngClass Directive: src/pages/home/home.html

< ion-header>
  < ion-navbar>
    < ion-title>
      Company Names
    < /ion-title>
  < /ion-navbar>
< /ion-header>
 
< ion-content padding>
< ion-list no-lines>
  < ion-item *ngFor="let item of items; let i = index;"
             [ngClass]="{'bold': (i % 2 == 0)}">
    {{i+1}}. {{item}}
  < /ion-item>
< /ion-list>
< /ion-content>

This is yet another way of doing the same thing which we did using ternary operator above. Here, if i % 2 is equal to zero, then bold class will be applied, if not it won’t be applied.

changing colors: src/pages/home/home.scss

page-home {
    .bold{
        font-weight: bolder;
        color: blue;
    }
    .normal{
        font-weight: normal;
        color: green;
    }
}

Alternatively the list items appear in bold and in normal font weight, along with blue and green colors respectively.

List Item Reordering: Ionic 2

Today lets learn how to implement reordering of list items in Ionic 2, using reorder directive and ionItemReorder event.

We’re using previous day code to implement reordering list items. So please go through these two small video tutorials before continuing .. (if you’re an advance user, then you can directly follow todays video tutorial).

1. Ionic Storage: Ionic 2
2. Pull To Refresh: Ionic 2

ionic 2 list item reorder

In this video tutorial lets learn
1. To build drag and rearrange interface and functionality.
2. Solve the ion-refresher component interference with the reorder directive.
3. Save rearranged data back to the database.

Reordering list items using reorder directive: Ionic 2



YouTube Link: https://www.youtube.com/watch?v=wKq4sKk5DXU [Watch the Video In Full Screen.]



reorder directive
We can implement reorder directive directly on ion-list. This way we apply reordering to the entire items present inside ion-list.

reorder on ion-list: src/pages/home/home.html

 < ion-list no-lines 
           reorder="true" 
           (ionItemReorder)="reorderItems($event);">
   < ion-item *ngFor="let item of items">
     {{item}}
   < /ion-item>
 < /ion-list>

But if we have ion-header, ion-footer and other items inside the list for which we do not want the reorder directive to be applied.
reorder on ion-item-group: src/pages/home/home.html

 < ion-list no-lines>
   < ion-list-header>Company Names
   < ion-item-group reorder="true" (ionItemReorder)="reorderItems($event);">
    < ion-item *ngFor="let item of items">
     {{item}}
    < /ion-item>
   < /ion-item-group>
 < /ion-list>

In that case we need to group those items on which we want the reordering, and then apply reorder directive on that group, as shown in above example.

reordering code: src/pages/home/home.ts

reorderItems(indexes){
 let element = this.items[indexes.from];
 this.items.splice(indexes.from, 1);
 this.items.splice(indexes.to, 0, element);
};

When the item is dragged and dropped to the new position, (ionItemReorder) event is emitted and this event also provides initial and new position index of the reordered item. Using this, we reorder the list items.

Above code snippet is a simple JavaScript code, where we first get the actual item value which is being reordered(using its index value – indexes.from) and store it in a temporary variable. Next we remove that item from the list. Finally we place that element in the new position. All these operation is done using simple JavaScript splice method.

Helper Function: src/pages/home/home.ts

import { reorderArray } from 'ionic-angular';
 
class MyComponent {
  items = [];
 
  reorderItems(indexes) {
    this.items = reorderArray(this.items, indexes);
  }
}

Ionic 2 also provides helper function called reorderArray to reorder the array of items. Here we import the helper class and then use it to reorder the array of items.

Helper Function: src/pages/home/home.html

< ion-list>
  < ion-list-header>Header< /ion-list-header>
  < ion-item-group reorder="true" (ionItemReorder)="$event.applyTo(items)">
    < ion-item *ngFor="let item of items">{{ item }}< /ion-item>
  < /ion-item-group>
< /ion-list>

We can execute helper function inside template as well, as shown above.

Reordering ON and OFF
src/pages/home/home.html

< ion-header>
  < ion-navbar>
    < ion-title>
      Company Names
    < /ion-title>
    < ion-buttons end>
      < button ion-button small clear (click)="actionBtn();">
        {{btnName}}
      < /button>
    < /ion-buttons>
  < /ion-navbar>
< /ion-header>
 
< ion-content padding>
 < ion-list no-lines>
   < ion-list-header>Company Names< /ion-list-header>
   < ion-item-group reorder="{{flag}}" 
                    (ionItemReorder)="reorderItems($event);">
   < ion-item *ngFor="let item of items">
     {{item}}
   < /ion-item>
   < /ion-item-group>
 < /ion-list>
< /ion-content>

Note that we have a button inside ion-header. We switch the value of btnName variable between ‘edit’ and ‘Done’ alternatively when the user clicks on it. Also we have assigned a variable(flag) to reorder directive. flag is of type Boolean and it also switches between ‘true’ and ‘false’ when the user clicks on btnName button. This way we enable and disable the visual drag and rearrange interface on the list items.

src/pages/home/home.ts

import { Component } from '@angular/core';
 
import { NavController } from 'ionic-angular';
import { Storage } from '@ionic/storage';
 
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
items: any;
btnName: any = 'edit';
flag: any = false;
  constructor(public navCtrl: NavController, public storage: Storage) {
    this.doRefresh(0);
  };
doRefresh(refresher){
    this.storage.get('myStore1').then((data) => {
      this.items = data;
 
      if(refresher != 0)
         refresher.complete();
    }); 
};
reorderItems(indexes){
 let element = this.items[indexes.from];
 this.items.splice(indexes.from, 1);
 this.items.splice(indexes.to, 0, element);
};
actionBtn(){
 if(this.btnName == 'edit')
 {
   this.btnName = 'Done';
   this.flag    = true;
 }
 else
 {
   this.btnName = 'edit';
   this.flag    = false;
   this.storage.set('myStore1', this.items);
 }
};
 
}

Here we initialize the btnName with a value of ‘edit’ and flag as ‘false’. So initially, the drag and rearrange interface will be disabled. Once the user clicks on the ‘edit’ button present inside ion-header, the visual drag and rearrange interface appears. After the rearrangement of the item is finished user needs to click on ‘Done’ button and we save the rearranged list items to our database. This way we can persist the rearranged data.

We could even save the data to database inside reorderItems() method itself, so that the data gets saved when the user drags and drops the item in its new position. Without the need for the user to click on ‘Done’ button.

actionBtn() method

actionBtn(){
 if(this.btnName == 'edit')
 {
   this.btnName = 'Done';
   this.flag    = true;
 }
 else
 {
   this.btnName = 'edit';
   this.flag    = false;
   this.storage.set('myStore1', this.items);
 }
};

Initially variable ‘btnName’ will be ‘edit’ and flag will be ‘false’. When the user clicks on ‘edit’ button, the label name changes to ‘Done’ and the flag value changes to ‘true’. By this, the drag and rearrange interface appears on the list items. Once the arrangement is done, the user needs to click on the button ‘Done’. When the user clicks on ‘Done’ button, the button label or name changes back to ‘edit’ and the visual drag and rearrange interface gets disabled and optionally we save the rearranged data back to the database.

item reordering and ion-refresher conflict

< ion-header>
  < ion-navbar>
    < ion-title>
      Company Names
    < /ion-title>
    < ion-buttons end>
      < button ion-button small clear (click)="actionBtn();">
        {{btnName}}
      < /button>
    < /ion-buttons>
  < /ion-navbar>
< /ion-header>
 
< ion-content padding>
  < ion-refresher (ionRefresh)="doRefresh($event);">
    < ion-refresher-content 
      pullingText="Pull to refresh"
      pullingIcon="arrow-dropdown"
      refreshingSpinner="circles"
      refreshingText="..fetching">
    < /ion-refresher-content>
 < /ion-refresher>
 
 < ion-list no-lines>
   < ion-list-header>Company Names< /ion-list-header>
   < ion-item-group reorder="true" 
                    (ionItemReorder)="reorderItems($event);">
   < ion-item *ngFor="let item of items">
     {{item}}
   < /ion-item>
   < /ion-item-group>
 < /ion-list>
< /ion-content>

This code has both ion-refresher as well as reorder directive. Here when the user tries to drag an item downwards the refresher component gets invoked. To avoid that, we can simply disable ion-refresher when we enable reordering and enable ion-refresher when we disable reordering, as shown in below code.

Fixed: ion-refresher & item reorder

< ion-header>
  < ion-navbar>
    < ion-title>
      Company Names
    < /ion-title>
    < ion-buttons end>
      < button ion-button small clear (click)="actionBtn();">
        {{btnName}}
      < /button>
    < /ion-buttons>
  < /ion-navbar>
< /ion-header>
 
< ion-content padding>
  < ion-refresher (ionRefresh)="doRefresh($event);" 
                  *ngIf="flag == false">
    < ion-refresher-content 
      pullingText="Pull to refresh"
      pullingIcon="arrow-dropdown"
      refreshingSpinner="circles"
      refreshingText="..fetching">
    < /ion-refresher-content>
 < /ion-refresher>
 
 < ion-list no-lines>
   < ion-list-header>Company Names< /ion-list-header>
   < ion-item-group reorder="{{flag}}" 
                    (ionItemReorder)="reorderItems($event);">
   < ion-item *ngFor="let item of items">
     {{item}}
   < /ion-item>
   < /ion-item-group>
 < /ion-list>
< /ion-content>

Full Free Source Code: src/pages/home/home.html

< ion-header>
  < ion-navbar>
    < ion-title>
      Company Names
    < /ion-title>
    < ion-buttons end>
      < button ion-button small clear (click)="actionBtn();">
        {{btnName}}
      < /button>
    < /ion-buttons>
  < /ion-navbar>
< /ion-header>
 
< ion-content padding>
  < ion-refresher (ionRefresh)="doRefresh($event);" 
                  *ngIf="flag == false">
    < ion-refresher-content 
      pullingText="Pull to refresh"
      pullingIcon="arrow-dropdown"
      refreshingSpinner="circles"
      refreshingText="..fetching">
    < /ion-refresher-content>
 < /ion-refresher>
 
 < ion-list no-lines>
   < ion-list-header>Company Names< /ion-list-header>
   < ion-item-group reorder="{{flag}}" 
                    (ionItemReorder)="reorderItems($event);">
   < ion-item *ngFor="let item of items">
     {{item}}
   < /ion-item>
   < /ion-item-group>
 < /ion-list>
 
  < p>
    < ion-label fixed>Company Name< /ion-label>
    < ion-input type="text" name="company" [(ngModel)]="company">
    < /ion-input>
    < button ion-button (click)="save(company);">Add< /button>
  < /p>
< /ion-content>

Full Free Source Code: src/pages/home/home.ts

import { Component } from '@angular/core';
 
import { NavController } from 'ionic-angular';
import { Storage } from '@ionic/storage';
 
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
items: any;
btnName: any = 'edit';
flag: any = false;
  constructor(public navCtrl: NavController, public storage: Storage) {
    this.doRefresh(0);
  };
doRefresh(refresher){
    this.storage.get('myStore1').then((data) => {
      this.items = data;
 
      if(refresher != 0)
         refresher.complete();
    }); 
};
reorderItems(indexes){
 let element = this.items[indexes.from];
 this.items.splice(indexes.from, 1);
 this.items.splice(indexes.to, 0, element);
};
actionBtn(){
 if(this.btnName == 'edit')
 {
   this.btnName = 'Done';
   this.flag    = true;
 }
 else
 {
   this.btnName = 'edit';
   this.flag    = false;
   this.storage.set('myStore1', this.items);
 }
};
  save(val){
    console.log('data added '+val);
    this.storage.get('myStore1').then((data) => {
      if(data != null)
      {
        data.push(val);
        this.storage.set('myStore1', data);
      }
      else
      {
        let array = [];
        array.push(val);
        this.storage.set('myStore1', array);
      }
    });
  };
}

Example Application:
We’ve implemented the same code in one of our application ‘RSS Reader‘. Go to ‘Feed’ tab and add few blog / news sites rss feeds and the refresh the ‘Feed’ tab to see ‘list item reordering’ in action.

Pull To Refresh: Ionic 2

In today’s video tutorial, I’ll show you how to add ‘pull to refresh’ functionality to your Ionic 2 application. This works on the web(maybe as a progressive web app), on your real device, and even in simulators!

Before proceeding with today’s tutorial, please make sure to watch and understand Ionic Storage: Ionic 2. Because we’re implementing ‘pull to refresh’ for the same code we built for that tutorial.

Today we shall learn
1. How to add ‘pull to refresh’ functionality.
2. Also to customize the ‘pull to refresh’ outlook assets – like icons, text etc.

Adding ‘Pull To Refresh’ Functionality: Ionic 2



YouTube Link: https://www.youtube.com/watch?v=LBZQ-jHuQq0 [Watch the Video In Full Screen.]



Ion Refresher Code: src/pages/home/home.html

< ion-content>
  < ion-refresher (ionRefresh)="doRefresh($event);">
    < ion-refresher-content 
      pullingText="Pull to refresh"
      pullingIcon="arrow-dropdown"
      refreshingSpinner="circles"
      refreshingText="..fetching">
    < /ion-refresher-content>
 < /ion-refresher>
< /ion-content>

Here we add ion-refresher as first child of ion-content. This adds pull to refresh functionality on content component.

Once the user pulls down on the content area of the view, doRefresh method is called and it is passed with the refresher event, which has a method called complete(), when called, it collapses whatever is being shown on the screen by ion-refresher-content ( which is the child of ion-refresher ).

ionic refresh pull

Customize pull-to-refresh
We customize the look and feel of the pull to refresh functionality using ion-refresher-content‘s attributes. In our example, we have changed the default icon and have added text for both when the user pulls the content area down and while the fresh content is being fetched(before the complete() method is called in the home.ts component).

Related Read: ion-spinner Component: Ionic 2

ionic refresh leave

Note:
If we do not explicitly assign or change attributes on ion-refresher-content, it’ll behave according to the defaults of the operating system it’s working on.

Ion Refresher Code – default values for platforms: src/pages/home/home.html

< ion-content>
  < ion-refresher (ionRefresh)="doRefresh($event);">
    < ion-refresher-content>
    < /ion-refresher-content>
 < /ion-refresher>
< /ion-content>

doRefresh() method definition: src/pages/home/home.ts

doRefresh(refresher){
    this.storage.get('myStore').then((data) => {
      this.items = data;
 
      if(refresher != 0)
         refresher.complete();
    }); 
};

Once the doRefresh method is invoked by the view, we fetch the data and once done, we call complete() method on refresher object, which collapses whatever visual cues ionic is providing to the end user via ion-refresher-content.

Full Free Source Code: src/pages/home/home.html

< ion-header>
  < ion-navbar>
    < ion-title>
      Ionic Blank
    < /ion-title>
  < /ion-navbar>
< /ion-header>
 
< ion-content padding>
  < ion-refresher (ionRefresh)="doRefresh($event);">
    < ion-refresher-content 
      pullingText="Pull to refresh"
      pullingIcon="arrow-dropdown"
      refreshingSpinner="circles"
      refreshingText="..fetching">
    < /ion-refresher-content>
 < /ion-refresher>
  < p *ngFor="let item of items">
    {{item}}
  < /p>
  < p>
    < ion-label fixed>Company Name< /ion-label>
    < ion-input type="text" name="company" [(ngModel)]="company">
    < /ion-input>
    < button ion-button (click)="save(company);">Add< /button>
  < /p>
< /ion-content>

Full Free Source Code: src/pages/home/home.ts

import { Component } from '@angular/core';
 
import { NavController } from 'ionic-angular';
import { Storage } from '@ionic/storage';
 
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
items: any;
  constructor(public navCtrl: NavController, public storage: Storage) {
    this.doRefresh(0);
  };
doRefresh(refresher){
    this.storage.get('myStore').then((data) => {
      this.items = data;
 
      if(refresher != 0)
         refresher.complete();
    }); 
};
  save(val){
    console.log('data added '+val);
    this.storage.get('myStore').then((data) => {
      if(data != null)
      {
        data.push(val);
        this.storage.set('myStore', data);
      }
      else
      {
        let array = [];
        array.push(val);
        this.storage.set('myStore', array);
      }
    });
  };
}

Here we need to call doRefresh() method inside the constructor too, without which the application will not have any data when its loaded for the first time – until the user pulls the content view and invokes doRefresh() method. To avoid such inconvenience, we call doRefresh() method inside the constructor and pass in ZERO as its parameter – this way we can bypass calling complete() method whenever the data being passed to doRefresh() method is ZERO.