Ionic 2 & 3 - SQLite servis

Ionic 2 & 3 – SQLite servis

Ovaj blog post je nastavak prethodnog pod naslovom Ionic 2SQLite za trajno spremanje podataka. Iako sam ondje već obradio temu spremanja podataka u lokalnu bazu podataka i prikaz tih podataka kada aplikacija nije povezana s mrežom važno je znati da postoji i bolji način kako to napraviti.

Kreiranjem SQLite servisa svu logiku vezanu uz kreiranje i korištenje lokalne baze podataka imamo na jednom mjestu.

Instalacija SQLite plugina

Plugin instalirate naredbama

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

Više o SQLite pluginu na adresi https://github.com/litehelpers/Cordova-sqlite-storage

Kreiranje SQLite servisa

Servis kreirate naredbom

$ ionic g provider MyData

Cilj ovog DatabaseService servisa je da na jednom mjestu kreiramo sve potrebne tablice te da ih uz što manje ponavljanja koda koristimo u ostatku aplikacije.

Unutar konstuktora kreiramo tablice mojaTablica i mojaDrugaTablica.

Funkcionalnosti poput spremanja u lokalnu bazu, čitanja iz nje i brisanja spremamo u posebne funkcije, kao što su npr saveTablicaToSqlite(), getTablicaMyOfflineData() i deleteTablicaMyOfflineData(), koje onda možemo pozivati u ostatku aplikacije.

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Platform } from 'ionic-angular';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite';

@Injectable()
export class DatabaseService {

  db:any;
  private isOpen: boolean;

  //Konstruktor početak
  constructor(public _http: Http, public _platform: Platform, private sqlite: SQLite) {
    console.log('Hello Database Provider');

    this._platform.ready().then(() => {

     if(!this.isOpen) {
            this.sqlite = new SQLite();
            this.sqlite.create({name: "baza.db", location: "default"}).then((db: SQLiteObject) => {
                 //Prva tablica
                 db.executeSql('CREATE TABLE IF NOT EXISTS mojaTablica (mojaTablicaId INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, user_name TEXT, location TEXT)', {})
                 .then(() => console.log('Executed SQL - PrvaTablica'))
                 .catch(e => console.log(e));
                 //Druga tablica
                 db.executeSql('CREATE TABLE IF NOT EXISTS mojaDrugaTablica (mojaDrugaTablicaId INTEGER PRIMARY KEY AUTOINCREMENT, firstname TEXT, lastname TEXT)', {})
                 .then(() => console.log('Executed SQL - DrugaTablica'))
                 .catch(e => console.log(e));
             })
             .catch(e => console.log(e));
     } 
     

     });
  }
  //Konstruktor kraj
   //////////Tablica\\\\\\\\\\
   //SPREMI
    public saveTablicaToSqlite(DataArray){
	  this.sqlite.create({
      name: 'baza.db',
      location: 'default'
      })
      .then((db: SQLiteObject) => {
           db.executeSql("INSERT INTO mojaTablica (name, user_name, location) VALUES (?,?,?)", [DataArray.name, DataArray.user_name, DataArray.location]).then((data) => {
           console.log("INSERTED: " + JSON.stringify(data));
           }, (error) => {
           console.log("ERROR kod inserta: " + JSON.stringify(error.err));
        });
	  })
     .catch(e => console.log(e));
    }
    //DOHVATI
    public getTablicaMyOfflineData() {
        return new Promise((resolve, reject) => {
          this.sqlite.create({
          name: 'baza.db',
          location: 'default'
          })
          .then((db: SQLiteObject) => {
            db.executeSql("SELECT * FROM mojaTablica", []).then((data) => {
                let DataArray = [];
                if(data.rows.length > 0) {
                    for(let i = 0; i < data.rows.length; i++) {
                        DataArray.push({
                            name: data.rows.item(i).name,
                            user_name: data.rows.item(i).user_name,
                            location: data.rows.item(i).location
                        });
                    }
                }
                resolve(DataArray);
            }, (error) => {
                reject(error);
            });
          })
         .catch(e => console.log(e));
        });
    }
    //OBRIŠI
    public deleteTablicaMyOfflineData(){
	  this.sqlite.create({
      name: 'baza.db',
      location: 'default'
      })
      .then((db: SQLiteObject) => {
           db.executeSql("DELETE FROM mojaTablica",[]).then((data) => {
           console.log("DELETED: " + JSON.stringify(data));
           }, (error) => {
           console.log("ERROR kod brisanja: " + JSON.stringify(error.err));
        });
	 })
     .catch(e => console.log(e));
    }
   //////////DrugaTablica\\\\\\\\\\
   //SPREMI
    public saveToSqlite(DataArrayTwo){
	  this.sqlite.create({
      name: 'baza.db',
      location: 'default'
      })
      .then((db: SQLiteObject) => {
           db.executeSql("INSERT INTO mojaDrugaTablica (firstname, lastname) VALUES (?,?)", [DataArrayTwo.firstname, DataArrayTwo.lastname]).then((data) => {
           console.log("INSERTED: " + JSON.stringify(data));
           }, (error) => {
           console.log("ERROR kod inserta: " + JSON.stringify(error.err));
        });
	  })
     .catch(e => console.log(e));
    }
    //DOHVATI
    public getMyOfflineData() {
        return new Promise((resolve, reject) => {
          this.sqlite.create({
          name: 'baza.db',
          location: 'default'
          })
          .then((db: SQLiteObject) => {
            db.executeSql("SELECT * FROM mojaDrugaTablica", []).then((data) => {
                let LocalArrayTwo = [];
                if(data.rows.length > 0) {
                    for(let i = 0; i < data.rows.length; i++) {
                        LocalArrayTwo.push({
                            firstname: data.rows.item(i).firstname,
                            lastname: data.rows.item(i).lastname
                        });
                    }
                }
                resolve(LocalArrayTwo);
            }, (error) => {
                reject(error);
            });
          })
         .catch(e => console.log(e));
        });
    }
    //OBRIŠI
    public deleteMyOfflineData(){
	  this.sqlite.create({
      name: 'baza.db',
      location: 'default'
      })
      .then((db: SQLiteObject) => {
           db.executeSql("DELETE FROM mojaDrugaTablica",[]).then((data) => {
           console.log("DELETED: " + JSON.stringify(data));
           }, (error) => {
           console.log("ERROR kod brisanja: " + JSON.stringify(error.err));
        });
	 })
     .catch(e => console.log(e));
    }

  }

Kako bi ovaj servis mogli koristiti trebamo ga navesti u app.module.ts

import { DatabaseService } from '../providers/my-data';
import { SQLite } from '@ionic-native/sqlite';
...
 providers: [StatusBar, 
             SplashScreen,
             DatabaseService, 
             SQLite, 
             {provide: ErrorHandler, useClass: IonicErrorHandler}]

Korištenje SQLite baze u ostatku aplikacije

Ranije kreiran SQLite servis sada možemo koristiti u ostatku aplikacije za spremanje podataka koje onda možemo prikazivati korisnicima kada aplikacije nije povezana s mrežom.

Recimo da u ovom primjeru na početnoj stranici želimo povući žive podatke s API-ja dok je aplikacije povezana s mrežom i odmah ih spremiti u SQLite bazu kako bi ih mogli koristiti kada se povezanost s mrežom izgubi.

Kada se otvori home.ts i pokrene funkcija storeMyOfflineData() pozvat će se funkcija getMyLiveDataFromApi() koja dovlači vanjske podatke u mobilnu aplikaciju. Te podatke u tom trenutku odmah možemo prikazati korisnicima. Istovremeno, pozivamo _database.saveTablicaToSqlite servis kojemu prosljeđujemo niz podataka this.DataArray[i] koje smo dobili iz API-ja.

import { Component } from '@angular/core';
import { NavController, IonicPage } from 'ionic-angular';
import { ApiProvider } from '../../providers/api-providers';
import { DatabaseService } from "../../providers/database-service";

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
  providers: [ApiProvider]
})
export class HomePage {

  public DataArray: Array<Object>;

  //Podaci potrebni API-ju da bi vratio podatke
  parameters = { user_id: localStorage.getItem('user_id'), access_token: localStorage.getItem('access_token') };

  constructor(public _navCtrl: NavController, 
              public _api: ApiProvider,
              public _database: DatabaseService) {
  }
  
   //Spremi žive podatke u lokalnu SQLite bazu
    storeMyOfflineData(){
         this._api.getMyLiveDataFromApi(this.parameters).subscribe(res => {
          this.DataArray = res;
          if(res.length > 0) {
                for(var i = 0; i < res.length; i++) {
                  this._database.saveTablicaToSqlite(this.DataArray[i]);
                }
          }
           }); 
    }
	
	//Prikaži lokalne podatke
	 getMyOfflineData(){
       this._database.getTablicaMyOfflineData().then((result) => {
            this.DataArray = <Array<Object>> result;
        }, (error) => {
            console.log("ERROR: ", error);
        });
    } 
	
	 //Isprazni lokalnu bazu
     deleteMyOfflineData() {
       this._database.deleteTablicaMyOfflineData();
    } 

}

Testiranje na mobilnom uređaju

Uspješnost kreiranja SQLite baze kao i korištenje najbolje ćete testirati na fizičkom uređaju. Spojite uređaj na PC, pokrenite naredbu

$ ionic run android

i otvorite chrome://inspect/#devices u Chrome web pregledniku. Ondje ćete vidjeti svoj mobilni uređaj na kojemu je pokrenuta aplikacija. Ispod imena aplikacije kliknite na inspect.

Sada u konzoli možete vidjeti da su SQLite tablice uspješno kreiranje.

Ionic 2 & 3 – SQLite servis - kreiranje tablice

Dalje, kada se otvori početna stranica može se vidjeti da se otvara baza i da se spremaju podaci. Sljedeći put kada opet otvorimo početnu stranicu, brišu se iz lokalne baze do tada spremljni podaci i dodaju se svježi podaci.

SQLite servis - brisanje i spremanje

Zaključak

Usporedite prethodni blog post i ovaj pa zaključite koji je način korištenja SQLite baze bolji. Moje mišljenje je da je bolji način korištenje servisa jer tako ne moramo ponavljati jedan te isti kod u ostatku aplikacije nego samo pozivamo funkcije za spremanje, čitanje i brisanje lokalnih podataka.

Objavio

Tomislav Stanković

Bloger širokog raspona interesa od kojih dio voli objaviti na ovom blogu. U neslobodno vrijeme Angular developer mobilnih i web aplikacija.

11 misli o “Ionic 2 & 3 – SQLite servis”

  1. Možeš li objasniti ukratko ovaj dio koda;
    parameters = { user_id: localStorage.getItem(‘user_id’), access_token: localStorage.getItem(‘access_token’) };
    To su podaci potrebni za sinkronizaciju, a pohranjeni lokalno?
    Volila bi post o login-u korisnika (s SQLite-om). Ty!


    14/07/2017 u 13:51

    I blog post o sinkronizaciji SQLite podataka s online bazom podataka.

    1. Da, u ovom primjeru, to su podaci potrebni kako bi API vratio rezultat inače bi vratio error, a dobio sam ih u trenutku kada se korisnik prijavi u aplikaciju i spremio u localStorage.

      Naravno, ne mora svaki API imati takve parametre (npr. RandomUser API iz primjera na https://www.tomislavstankovic.com/blog/ionic2-prikaz-json-podatak-api/) i kad bolje razmislim možda je najbolje da maknem parameters objekt iz ovog primjera da bezveze ne zbunjuje ljude.

      Što se logina/prijave tiče možeš pogledati https://www.tomislavstankovic.com/blog/ionic-firebase-registracija-prijava/. Mogu eventualno napraviti primjer NodeJS API-ja za prijavu koji se onda može koristiti za Ionic aplikaciju jer logika unutar aplikacije ostaje ista – dva polja za prijavu (korisničko ime i lozinka).

  2. Hvala puno, na tvom blogu našla sam većinom sve što mi je potrebno za napraviti aplikaciju.

  3. import { ApiProvider } from ‘../../providers/api-providers’;

    where you calling the ApiProvider in this program?
    pls reply as soon as possible.

  4. Really fantastic tutor.
    I don’t know if the author is still active. Coz i want to ask something about this tutor (related to online/offline and sync database).
    If the author is still active. Plz let me know.
    Regards.

Odgovori

Vaša adresa e-pošte neće biti objavljena. Obavezna polja su označena sa *