Ovaj blog post je nastavak prethodnog pod naslovom Ionic 2 – SQLite 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
1 2 |
$ 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
1 |
$ 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
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
1 2 3 4 5 6 7 8 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
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
1 |
$ 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.
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.
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.
Hvala puno za post!
Hvala tebi Nives na posjeti i komentaru. Ako imaš prijedlog za temu o kojoj bi htjela da objavim blog post slobodno reci.
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.
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).
Hvala puno, na tvom blogu našla sam većinom sve što mi je potrebno za napraviti aplikaciju.
import { ApiProvider } from ‘../../providers/api-providers’;
where you calling the ApiProvider in this program?
pls reply as soon as possible.
Here you can see example of how to create provider https://www.tomislavstankovic.com/blog/ionic2-prikaz-json-podatak-api/
Very nice, thanks and hugs, from Fortaleza, Ceará – Brazil!
You’re welcome. I’m curious, since my blog is not in English I’m interested in how you came to my blog, through Google or Stackoverflow?
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.
I’m still active. Feel free to ask.