Como fazer um CRUD com SQLite no Ionic

Nessa vídeo aula eu mostro como incluir, alterar, excluir e consultar dados no SQLite com Ionic.

 

O que é o SQLite

Segundo o próprio site do SQLite, O SQLite é um motor de banco de dados SQL autônomo, de alta confiabilidade, incorporado, completo e de domínio público. O SQLite é o mecanismo de banco de dados mais utilizado no mundo.

 

Criando uma aplicação de exemplo

No vídeo acima e mostro como criar um app para salvar produtos utilizando o SQLite.

O passo a passo abaixo é o mesmo mostrado no vídeo.

  • Passo 1: Criar o aplicativo.
  • Passo 2: Instalar o plugin do SQLite.
  • Passo 3: Adicionar a plataforma Android/iOS.
  • Passo 4: Configurar o aplicativo.
  • Passo 5: Criar o provider para criação do banco de dados.
  • Passo 6: Inicializar a criação do banco de dados quando o app startar.
  • Passo 7: Criar o provider para o CRUD de produtos.
  • Passo 8: Criar o provider para listar as categorias.
  • Passo 9: Alterar a pagina Home para listar, excluir e pesquisar produtos.
  • Passo 10: Criar a pagina de inclusão/alteração de produtos.

 

Passo 1: Criar o aplicativo

ionic start NOME_DO_APP blank

 

Passo 2: Instalar o plugin do SQLite

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

 

Passo 3: Adicionar a plataforma Android/iOS

ionic cordova platform add android
ionic cordova platform add ios

 

Passo 4: Configurar o aplicativo

Arquivo app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule, LOCALE_ID } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

import { SQLite } from '@ionic-native/sqlite'
import { DatabaseProvider } from '../providers/database/database';
import { ProductProvider } from '../providers/product/product';
import { CategoryProvider } from '../providers/category/category';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    // Grande sacada para formatar numeros e datas no formato brasileiro
    {provide: LOCALE_ID, useValue: 'pt-BR'},
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    SQLite,
    DatabaseProvider,
    ProductProvider,
    CategoryProvider
  ]
})
export class AppModule {}

 

Passo 5: Criar o provider para criação do banco de dados

ionic g provider database

 

Arquivo database.ts

import { Injectable } from '@angular/core';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite';

@Injectable()
export class DatabaseProvider {

  constructor(private sqlite: SQLite) { }

  /**
   * Cria um banco caso não exista ou pega um banco existente com o nome no parametro
   */
  public getDB() {
    return this.sqlite.create({
      name: 'products.db',
      location: 'default'
    });
  }

  /**
   * Cria a estrutura inicial do banco de dados
   */
  public createDatabase() {
    return this.getDB()
      .then((db: SQLiteObject) => {

        // Criando as tabelas
        this.createTables(db);

        // Inserindo dados padrão
        this.insertDefaultItems(db);

      })
      .catch(e => console.log(e));
  }

  /**
   * Criando as tabelas no banco de dados
   * @param db
   */
  private createTables(db: SQLiteObject) {
    // Criando as tabelas
    db.sqlBatch([
      ['CREATE TABLE IF NOT EXISTS categories (id integer primary key AUTOINCREMENT NOT NULL, name TEXT)'],
      ['CREATE TABLE IF NOT EXISTS products (id integer primary key AUTOINCREMENT NOT NULL, name TEXT, price REAL, duedate DATE, active integer, category_id integer, FOREIGN KEY(category_id) REFERENCES categories(id))']
    ])
      .then(() => console.log('Tabelas criadas'))
      .catch(e => console.error('Erro ao criar as tabelas', e));
  }

  /**
   * Incluindo os dados padrões
   * @param db
   */
  private insertDefaultItems(db: SQLiteObject) {
    db.executeSql('select COUNT(id) as qtd from categories', {})
    .then((data: any) => {
      //Se não existe nenhum registro
      if (data.rows.item(0).qtd == 0) {

        // Criando as tabelas
        db.sqlBatch([
          ['insert into categories (name) values (?)', ['Hambúrgueres']],
          ['insert into categories (name) values (?)', ['Bebidas']],
          ['insert into categories (name) values (?)', ['Sobremesas']]
        ])
          .then(() => console.log('Dados padrões incluídos'))
          .catch(e => console.error('Erro ao incluir dados padrões', e));

      }
    })
    .catch(e => console.error('Erro ao consultar a qtd de categorias', e));
  }
}

 

Passo 6: Inicializar a criação do banco de dados quando o app startar

Arquivo app.component.ts

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { HomePage } from '../pages/home/home';
import { DatabaseProvider } from '../providers/database/database'

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage: any = null;

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, dbProvider: DatabaseProvider) {
    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.
      statusBar.styleDefault();

      //Criando o banco de dados
      dbProvider.createDatabase()
        .then(() => {
          // fechando a SplashScreen somente quando o banco for criado
          this.openHomePage(splashScreen);
        })
        .catch(() => {
          // ou se houver erro na criação do banco
          this.openHomePage(splashScreen);
        });
    });
  }

  private openHomePage(splashScreen: SplashScreen) {
    splashScreen.hide();
    this.rootPage = HomePage;
  }
}

 

Passo 7: Criar o provider para o CRUD de produtos

Arquivo product.ts

import { Injectable } from '@angular/core';
import { SQLiteObject } from '@ionic-native/sqlite';
import { DatabaseProvider } from '../database/database';

@Injectable()
export class ProductProvider {

  constructor(private dbProvider: DatabaseProvider) { }

  public insert(product: Product) {
    return this.dbProvider.getDB()
      .then((db: SQLiteObject) => {
        let sql = 'insert into products (name, price, duedate, active, category_id) values (?, ?, ?, ?, ?)';
        let data = [product.name, product.price, product.duedate, product.active ? 1 : 0, product.category_id];

        return db.executeSql(sql, data)
          .catch((e) => console.error(e));
      })
      .catch((e) => console.error(e));
  }

  public update(product: Product) {
    return this.dbProvider.getDB()
      .then((db: SQLiteObject) => {
        let sql = 'update products set name = ?, price = ?, duedate = ?, active = ?, category_id = ? where id = ?';
        let data = [product.name, product.price, product.duedate, product.active ? 1 : 0, product.category_id, product.id];

        return db.executeSql(sql, data)
          .catch((e) => console.error(e));
      })
      .catch((e) => console.error(e));
  }

  public remove(id: number) {
    return this.dbProvider.getDB()
      .then((db: SQLiteObject) => {
        let sql = 'delete from products where id = ?';
        let data = [id];

        return db.executeSql(sql, data)
          .catch((e) => console.error(e));
      })
      .catch((e) => console.error(e));
  }

  public get(id: number) {
    return this.dbProvider.getDB()
      .then((db: SQLiteObject) => {
        let sql = 'select * from products where id = ?';
        let data = [id];

        return db.executeSql(sql, data)
          .then((data: any) => {
            if (data.rows.length > 0) {
              let item = data.rows.item(0);
              let product = new Product();
              product.id = item.id;
              product.name = item.name;
              product.price = item.price;
              product.duedate = item.duedate;
              product.active = item.active;
              product.category_id = item.category_id;

              return product;
            }

            return null;
          })
          .catch((e) => console.error(e));
      })
      .catch((e) => console.error(e));
  }

  public getAll(active: boolean, name: string = null) {
    return this.dbProvider.getDB()
      .then((db: SQLiteObject) => {
        let sql = 'SELECT p.*, c.name as category_name FROM products p inner join categories c on p.category_id = c.id where p.active = ?';
        var data: any[] = [active ? 1 : 0];

        // filtrando pelo nome
        if (name) {
          sql += ' and p.name like ?'
          data.push('%' + name + '%');
        }

        return db.executeSql(sql, data)
          .then((data: any) => {
            if (data.rows.length > 0) {
              let products: any[] = [];
              for (var i = 0; i < data.rows.length; i++) {
                var product = data.rows.item(i);
                products.push(product);
              }
              return products;
            } else {
              return [];
            }
          })
          .catch((e) => console.error(e));
      })
      .catch((e) => console.error(e));
  }
}

export class Product {
  id: number;
  name: string;
  price: number;
  duedate: Date;
  active: boolean;
  category_id: number;
}

 

Passo 8: Criar o provider para listar as categorias

Arquivo category.ts

import { Injectable } from '@angular/core';
import { SQLiteObject } from '@ionic-native/sqlite';
import { DatabaseProvider } from '../database/database';

@Injectable()
export class CategoryProvider {

  constructor(private dbProvider: DatabaseProvider) { }

  public getAll() {
    return this.dbProvider.getDB()
    .then((db: SQLiteObject) => {

      return db.executeSql('select * from categories', [])
        .then((data: any) => {
          if (data.rows.length > 0) {
            let categories: any[] = [];
            for (var i = 0; i < data.rows.length; i++) {
              var category = data.rows.item(i);
              categories.push(category);
            }
            return categories;
          } else {
            return [];
          }
        })
        .catch((e) => console.error(e));
    })
    .catch((e) => console.error(e));
  }
}

 

Passo 9: Alterar a pagina Home para listar, excluir e pesquisar produtos

Arquivo home.ts

import { Component } from '@angular/core';
import { NavController, ToastController } from 'ionic-angular';
import { ProductProvider, Product } from '../../providers/product/product'

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  products: any[] = [];
  onlyInactives: boolean = false;
  searchText: string = null;

  constructor(public navCtrl: NavController, private toast: ToastController, private productProvider: ProductProvider) { }

  ionViewDidEnter() {
    this.getAllProducts();
  }

  getAllProducts() {
    this.productProvider.getAll(!this.onlyInactives, this.searchText)
      .then((result: any[]) => {
        this.products = result;
      });
  }

  addProduct() {
    this.navCtrl.push('EditProductPage');
  }

  editProduct(id: number) {
    this.navCtrl.push('EditProductPage', { id: id });
  }

  removeProduct(product: Product) {
    this.productProvider.remove(product.id)
      .then(() => {
        // Removendo do array de produtos
        var index = this.products.indexOf(product);
        this.products.splice(index, 1);
        this.toast.create({ message: 'Produto removido.', duration: 3000, position: 'botton' }).present();
      })
  }

  filterProducts(ev: any) {
    this.getAllProducts();
  }

}

 

Arquivo home.html

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic SQLite Example
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-searchbar (ionInput)="filterProducts($event)" [(ngModel)]="searchText"></ion-searchbar>
  <ion-list>
    <ion-item-sliding *ngFor="let product of products">

      <button ion-item (click)="editProduct(product.id)">
        <h1>{{ product.name }}</h1>
        <h2>{{ product.category_name }}</h2>
        <h2>{{ product.duedate | date:'dd/MM/yyyy' }}</h2>
        <h2 class="price">{{ product.price | currency:'BRL':true }}</h2>
      </button>

      <ion-item-options side="left">
        <button ion-button color="danger" (click)="removeProduct(product)">
          <ion-icon name="trash"></ion-icon>
          Excluir
        </button>
      </ion-item-options>

    </ion-item-sliding>
  </ion-list>

  <ion-fab right bottom>
    <button ion-fab color="light" (click)="addProduct()"><ion-icon name="add"></ion-icon></button>
  </ion-fab>

</ion-content>

<ion-footer>
  <ion-toolbar>
    <p>Total: {{ products.length }}</p>
    <ion-list>
      <ion-item no-lines>
        <ion-label>Listar inativos</ion-label>
        <ion-toggle name="listarInativos" [(ngModel)]="onlyInactives" (ionChange)="getAllProducts()"></ion-toggle>
      </ion-item>
    </ion-list>
  </ion-toolbar>
</ion-footer>

 

Arquivo home.scss

.price {
  color: color($colors, secondary);
}

 

Passo 10: Criar a pagina de inclusão/alteração de produtos

ionic g page edit-product

 

Arquivo edit-product.ts

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ToastController } from 'ionic-angular';
import { ProductProvider, Product } from '../../providers/product/product'
import { CategoryProvider } from '../../providers/category/category'

@IonicPage()
@Component({
  selector: 'page-edit-product',
  templateUrl: 'edit-product.html',
})
export class EditProductPage {
  model: Product;
  categories: any[];

  constructor(
    public navCtrl: NavController, public navParams: NavParams,
    private toast: ToastController, private productProvider: ProductProvider,
    private categoryProvider: CategoryProvider) {

    this.model = new Product();

    if (this.navParams.data.id) {
      this.productProvider.get(this.navParams.data.id)
        .then((result: any) => {
          this.model = result;
        })
    }
  }

  /**
   * Runs when the page has loaded
   */
  ionViewDidLoad() {
    this.categoryProvider.getAll()
      .then((result: any[]) => {
        this.categories = result;
      })
      .catch(() => {
        this.toast.create({ message: 'Erro ao carregar as categorias.', duration: 3000, position: 'botton' }).present();
      });
  }

  save() {
    this.saveProduct()
      .then(() => {
        this.toast.create({ message: 'Produto salvo.', duration: 3000, position: 'botton' }).present();
        this.navCtrl.pop();
      })
      .catch(() => {
        this.toast.create({ message: 'Erro ao salvar o produto.', duration: 3000, position: 'botton' }).present();
      });
  }

  private saveProduct() {
    if (this.model.id) {
      return this.productProvider.update(this.model);
    } else {
      return this.productProvider.insert(this.model);
    }
  }

}

 

Arquivo edit-product.html

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic SQLite Example
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>

  <ion-list>

    <ion-item>
      <ion-label stacked>Nome</ion-label>
      <ion-input type="text" name="name" [(ngModel)]="model.name"></ion-input>
    </ion-item>

    <ion-item>
      <ion-label stacked>Preço</ion-label>
      <ion-input type="number" name="price" [(ngModel)]="model.price"></ion-input>
    </ion-item>

    <ion-item>
      <ion-label stacked>Vencimento</ion-label>
      <ion-datetime displayFormat="DD/MM/YYYY" name="duedate" min="2017" max="2020-12-31" [(ngModel)]="model.duedate"></ion-datetime>
    </ion-item>

    <ion-item>
      <ion-label stacked>Categoria</ion-label>
      <ion-select name="category_id" [(ngModel)]="model.category_id">
        <ion-option *ngFor="let category of categories" value="{{ category.id }}">{{ category.name}}</ion-option>
      </ion-select>
    </ion-item>

    <ion-item>
      <ion-label>Ativo</ion-label>
      <ion-checkbox name="active" [(ngModel)]="model.active"></ion-checkbox>
    </ion-item>

  </ion-list>

  <button ion-button block (click)="save()">Salvar</button>

</ion-content>

 

Clique no botão abaixo para ver o código fonte gerado nessa aula

 

Código fonte gerado na aula

 

Referências

 

Gostou desse artigo? Aproveite e curta e compartilhe para que mais pessoas possam também visualiza-lo!

Ainda ficou alguma dúvida ou tem alguma sugestão? Deixa aí nos comentários!