Neste post, iremos implementar algumas funções basicas do SQLite no ionic 3 utilizando um directive de calendario.
Índice
Instalações necessárias:
- npm install ionic2-calendar –save [ para mais informações clique aqui ]
- npm install moment –save [ para mais informações clique aqui ]
- npm install intl@1.2.5 –save
Preparar aplicativo:
No app.module.ts
coloque estes import’s:
import { NgModule, ErrorHandler, LOCALE_ID } from '@angular/core';
import { HttpModule } from '@angular/http';
import { NgCalendarModule } from 'ionic2-calendar';
import { SQLite } from '@ionic-native/sqlite';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
...
@NgModule({
...
imports: [
HttpModule,
NgCalendarModule,
],
...
providers: [
{provide: ErrorHandler, useClass: IonicErrorHandler},
{ provide: LOCALE_ID, useValue: 'pt-Br' },
SQLite,
]
...
OBS: Caso os nomes dos meses não sejam traduzidos para sua língua sugiro por dentro dos import’s do @NgModule
um array com os nomes como abaixo
IonicModule.forRoot(MyApp, {
monthNames: ['janeiro', 'fevereiro', 'mar\u00e7o', ... ],
monthShortNames: ['jan', 'fev', 'mar', ... ],
dayNames: ['domingo', 'segunda-feira', 'ter\u00e7a-feira', ... ],
dayShortNames: ['dom', 'seg', 'ter', ... ],
})
Avalie qual pode se encaixar melhor no seu projeto!
Criar componentes:
Vamos para o terminal
e criar as telas e os providers:
$ ionic g page Calendar <!-- escolha o nome da sua preferencia -->
$ ionic g page event-modal <!-- escolha o nome da sua preferencia -->
$ ionic g provider database
$ ionic g provider event
Pegue o exemplo de CRUD neste post aqui
Métodos:
Agora com um CRUD já feito podemos chamar cada função nas nossas telas primeiramente vamos para a calendar (ou o nome que você preferiu), primeiro item que vamos mexer é colocar o calendar para funcionar sendo assim vamos no .html
e colocamos a tag:
<calendar [eventSource]="eventSource"
[noEventsLabel]="noEventsLabel"
[calendarMode]="calendar.mode"
[currentDate]="calendar.currentDate"
[locale]="calendar.locale"
[monthviewEventDetailTemplate]="template"
(onEventSelected)="onEventSelected($event)"
(onTitleChanged)="onViewTitleChanged($event)"
(onTimeSelected)="onTimeSelected($event)"
step="30"
class="calendar">
</calendar>
Agora no .ts
podemos pôr os eventos e variáveis necessárias:
...
import { IonicPage, NavController, NavParams, ModalController, AlertController } from 'ionic-angular';
import * as moment from 'moment';
import { EventProvider } from '../../providers/event/event';]
...
export class CalendarPage {
eventSource = [];
viewTitle: string;
noEventsLabel: string = "Não há eventos listados";
selectedDay = new Date();
calendar = {
mode: 'month',
locale: 'pt-br',
currentDate: new Date()
};
constructor(public navCtrl: NavController, public navParams: NavParams, private modalCtrl: ModalController, private alertCtrl: AlertController,
public ep: EventProvider) {
moment.locale('pt-br');
this.get();
}
Get()
Dentro do constructor chamamos a função do moment
locale para termos ele trabalhando no idioma em que estamos, mude ele para a sua necessidade. E também estamos iniciando a função get() que vamos criar agora:
get(){
this.ep.getAll()
.then((e: any[]) => {
for (let i = 0; i < e.length; i++) {
let ev = { id: e[i].id, title:e[i].title, startTime: new Date(e[i].startTime), endTime: new Date(e[i].endTime), allDay: e[i].allDay, notification: e[i].notification , subText: null };
this.eventSource.push(ev);
}
console.log(this.eventSource);
this.list(null);
})
.catch((e) => {console.error(e);});
}
Ela chama a promise getAll() do provider event.ts
e manipulamos o objeto retornado e onde temos um for
que corre todos os conteúdo de nosso objeto, colocando cada item na variável local ev e por fim dando um push no nosso array global eventSource ao termino do for
coloquei o console.log() só para termos certeza de como esta nosso array e ao fim do then temos nosso tratamento de erros, o catch.
List()
Antes do catch temos outra função sendo chamada a list() sendo incluída com o valor null vou demostrar agora o porquê:
list(data){
let eventData = data;
let events = this.eventSource;
if (data != null){
eventData.startTime = new Date(data.startTime);
eventData.endTime = new Date(data.endTime);
events.push(eventData);
}
for (let i = 0; i < events.length; i++) {
let element = events[i];
if(moment(element.startTime).format('L') == moment(element.endTime).format('L')){
if(element.allDay == true){
element.subText = 'O dia todo';
}else{
element.subText = moment(element.startTime).format('LTS');
}
} else if(parseInt(moment(element.endTime).format('DD')) > parseInt(moment(element.startTime).format('DD'))){
if(element.allDay == true){
element.subText = "O dia todo " + moment(element.startTime).format('L') +" || " + moment(element.endTime).format('L');
}else{
element.subText = moment(element.startTime).format('L') +' || ' + moment(element.endTime).format('L');
}
}
}
this.eventSource = [];
setTimeout(() => {
this.eventSource = events;
});
}
Esta função é para listar os eventos de cada dia dando uma informação rápida sobre o mesmo que é o item subText. Caso, a variável data
venha como null significa que já temos um subText para todos os eventos listados tornado a checagem pelo for
desnecessária (esta logica foi usada para evitar lentidão no app e possíveis erros)
Voltamos ao .html
e vamos adicionar os componentes para esta função fazer sentido:
<ng-template #template let-selectedDate="selectedDate.events" let-noEventsLabel="noEventsLabel">
<ion-list *ngIf="selectedDate.length > 0" no-lines class="event-list" padding>
<ion-list *ngFor="let event of selectedDate">
<ion-item-sliding>
<ion-item ion-item detail-push (click)="onEventSelected(event)" class="event-button">
<ion-icon name="calendar" item-start></ion-icon>
<h1></h1>
<p> </p>
</ion-item>
<ion-item-options side="right">
<button ion-button color="btnee" (click)="delete(event)">
delete
</button>
</ion-item-options>
<ion-item-options side="left">
<button ion-button color="btnee" (click)="edit(event)">
edit
</button>
</ion-item-options>
</ion-item-sliding>
</ion-list>
</ion-list>
<ion-title *ngIf="selectedDate.length == 0"><br></ion-title>
</ng-template>
Temos um ion-list com um if
da variável selectedDate que é uma variável do próprio calendar, por isso ela ainda não tinha sido mencionada, ela se comunica com o array eventSource pegando na função get() o que torna possível validarmos a existência com um > 0 assim criando outro ion-list para exibirmos os itens separados pela list() mostrando o title e o subText de cada evento cada um com dois button, um para delete() e outro para edit() (ambas funções que serão mostradas no próximo passos), e caso não tenha nenhum evento listado para o dia selecionado é mostrado o conteúdo da variável noEventsLabel. Isso tudo só é possível sendo colocado dentro da tag ng-template caso contrário ocorrerá erro na execução.
Create()
Antes disso vamos ver a tela onde podemos criar novos eventos:
addEvent() {
let modal = this.modalCtrl.create('EventModalPage', {selectedDay: this.selectedDay});
modal.present();
modal.onDidDismiss(data => {
if (data) {
this.ep.insert(data)
.then((res: any) => {
this.list(data);
})
.catch((e) => {console.error(e);});
}
});
}
Para criação temos que chamar a promise insert() do provider event.ts
que recebe o valor de data
onde temos a sulução do then que chama a outra função list() passando o data
novamente e temos nosso tratamento de erros, o catch. Mas antes disso temos que explicar de onde vem o objeto data
, ele é criado na page event-modal que chamamos pelo modalCtrl (caso, tenha algum problema em fazer esta chamada apague o import do event-modal no app.component.ts
). E vamos por o codigo nesta page no .html
:
<ion-header>
<ion-navbar>
<ion-buttons end>
<button ion-button icon-only (click)="cancel()">
<ion-icon name="close"></ion-icon>
</button>
</ion-buttons>
<ion-title>Adicionar Evento</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>
<ion-input type="text" placeholder="Titulo" [(ngModel)]="event.title"></ion-input>
</ion-item>
<ion-item>
<ion-label>Inicio</ion-label>
<ion-datetime color="bordas" displayFormat="DD/MM/YYYY HH:mm" pickerFormat="MMM D:HH:mm" [(ngModel)]="event.startTime" [min]="minDate"
cancelText="Cancelar"
doneText="Concluir"></ion-datetime>
</ion-item>
<ion-item>
<ion-label>Fim</ion-label>
<ion-datetime color="bordas" displayFormat="DD/MM/YYYY HH:mm" pickerFormat="MMM D:HH:mm" [(ngModel)]="event.endTime" [min]="event.startTime"
cancelText="Cancelar"
doneText="Concluir"></ion-datetime>
</ion-item>
<ion-item>
<ion-label>alarme</ion-label>
<ion-datetime displayFormat="HH:mm" pickerFormat="HH:mm" hourValues="0,1,2" minuteValues="0,1,15,30,45" [(ngModel)]="event.notification"
cancelText="Cancelar"
doneText="Concluir"
></ion-datetime>
</ion-item>
<ion-item>
<ion-label>Dia inteiro?</ion-label>
<ion-checkbox [(ngModel)]="event.allDay"></ion-checkbox>
</ion-item>
</ion-list>
<div>
<button ion-button block round (click)="save()">
Concluir
</button>
</div>
</ion-content>
Neste arquivo usamos a tag ion-datetime, caso não esteja familiarizado com este componente vá na documentação do ionic. Nesta tela criamos um Objeto event que será o retorno para data
no .ts
do calendar onde vamos manipular ele para enviar para o provider.
Mas neste momento temos que colocar algumas coisas no .ts
deste modal:
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular';
import * as moment from 'moment';
...
export class EventModalPage {
event = { id:null, title:null, startTime: moment(new Date()).format(), endTime: moment(new Date()).format(), allDay: false, notification: "00:00", subText: null };
minDate = moment(new Date()).format();
constructor(public navCtrl: NavController, public navParams: NavParams, public viewCtrl: ViewController) {
moment.locale('pt-br');
if(this.navParams.get('ev')){
let ev = this.navParams.get('ev');
this.event.id = ev.id;
this.event.allDay = ev.allDay;
this.event.endTime = moment(ev.endTime).format();
this.event.startTime = moment(ev.startTime).format();
this.event.subText = ev.subText;
this.event.notification = ev.notification;
this.event.title = ev.title;
}else{
let preselectedDate = moment(new Date()).format();
this.event.startTime = preselectedDate;
this.event.endTime = preselectedDate;
}
}
cancel() {
this.viewCtrl.dismiss();
}
save() {
this.viewCtrl.dismiss(this.event);
}
}
Aqui montamos o Objeto event que usamos no .html
anterior e temos um if
que fará sentido nas funções de delete() e edit() por já termos um objeto definido agora vamos para a próxima função.
Delete():
Nesta função temos que receber duas variáveis um Objeto ev
e uma booleana que por padrão vem como false:
delete(ev, act: boolean = false){
var idx = this.eventSource.indexOf(ev, 0);
if (idx != -1) {
this.eventSource.splice(idx, 1);
}
if(act == false){
this.ep.remove(ev.id)
.then((res: any) => {
this.list(null);
})
.catch((e) => {console.error(e);});
}
}
Primeiro verificamos a quantia de itens no eventSource, para depois usarmos o método splice do array
para remover o item selecionado. Chamamos a promise remove() onde enviamos unicamente o id para ser resolvida. Além de passarmos o valor null
para função list().
Edit():
Para esta só necessita enviar o objeto de event
edit(ev){
let modal = this.modalCtrl.create('EventModalPage', {ev: ev});
modal.present();
modal.onDidDismiss(data => {
if (data) {
this.ep.update(data)
.then((res: any) => {
this.delete(ev, true);
this.list(data);
})
.catch((e) => {console.error(e);});
}
});
}
Nesta função chamamos novamente o modal para podermos manipular os dados do event direto para o outro. Retomando o if
como estamos enviando event como ev ele recebe um dado e igualamos ao event do modal. E executando a promise update() para alterar tudo também chamamos a funções de delete() e list().
Na delete() removemos o item do array selecionado do eventSource e no list() inserimos o item com os dados atualizados.