Dopo aver
utilizzato viste e controller, vediamo i model, la terza componente del pattern MVCdi Titanium,
il cui compito è quello di fornire l'accesso ai dati che
utilizzeremo nell'applicazione.
Titanium utilizza Backbone.js
per implementare modelli e collezioni, per cui la documentazione
ufficiale di Appcelerator farà sempre riferimento a questa
libreria (in particolare alla versione 0.9.2).
Backbone.js
I modelli di Backbone sono una rappresentazione dei dati che
utilizzeremo nelle nostre app. Questi dati possono essere creati,
validati e salvati su una struttura di memorizzazione (generalmente un database,
ma non solo). I modelli hanno un sistema di eventi, ognuno dei quali
viene lanciato al verificarsi di determinate condizioni. Per
esempio, modificando un attributo del modello, Backbone lancerà
l'evento change che potrà essere intercettato e gestito.
È interessante, quindi, introdurre il termine collezione, col quale
intendiamo un insieme ordinato
di modelli che possono essere frutto di una interrogazione
(query) o più semplicemente rappresentare tutte le righe di
una tabella (nel caso in cui il nostro modello risulti associato
ad un database).
In questa lezione vedremo come implementare gli oggetti Backbone
nei progetti Titanium, come rappresentare i dati delle
nostre app utilizzando modelli e collezioni, come associarli alle
View e infine come caricare i dati e salvarli utilizzando gli adattatori (di cui parlaremo in seguito).
Creazione di un modello
Creiamo un progetto Alloy ex-novo ed attiviamo la funzione di menu
Alloy Model cliccando col pulsante destro del mouse sul
nome del progetto, nella colonna Project Explorer.
Ci verrà mostrata la finestra di definizione del modello, rappresentata nella figura seguente:
Compiliamo il modulo come descritto in figura, aggiungendo i
campi dello Schema uno alla volta con il pulsante verde.
Ciò consentirà la generazione del modello, e verrà creata la cartella app/models
che conterrà il file book.js.
exports.definition = {
config: {
columns: {
"title": "string",
"author": "string",
"isbn": "string"
},
adapter: {
type: "sql",
collection_name: "book"
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {
// extended functions and properties go here
});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {
// extended functions and properties go here
});
return Collection;
}
};
Il modello di questo esempio è composto da tre attributi (title, author,
isbn), che fanno riferimento ad una collezione book di tipo sql
(in questo caso sqllite che è utilizzato da Apple, Google
e Blackberry come database locale per i propri
sistemi operativi mobile).
Il modello prevede anche una sezione per essere esteso e per estendere le
sue collezioni con nuove funzionalità (per esempio validazioni
dei dati e ordinamenti
delle collezioni).
Implementare modelli e collezioni nei progetti Alloy
Scriviamo un'app che ci permetta, in modo semplice e spartano, di inserire
dei dati dentro una form, salvare questi dati sul
database e poterli leggere in modo sequenziale.
La nostra view index.xml pertanto sarà composta da tre campi
testuali e tre pulsanti (salva, precedente e successivo).
<Alloy>
<Window class="container" layout="vertical">
<TextField id="title" top="40" class="text" />
<TextField id="author" top="10" class="text"/>
<TextField id="isbn" top="10" class="text"/>
<Button id="save" top="10" title="salva" class="button" onClick="save"></Button>
<Button id="prev" top="10" title="precedente" class="button" onClick="prev"></Button>
<Button id="next" top="10" title="successivo" class="button" onClick="next"></Button>
</Window>
</Alloy>
Il foglio stile conterrà le definizioni delle classi container,
button e text.
".container": {
backgroundColor: "white"
},
".text": {
height: "40",
width: "90%",
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED
}
".button": {
height: "40",
width: "90%",
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED
}
.button e .text sono due classi fondamentalmente
uguali, ma si è preferito associare a ciascun widget una sua
classe per non confondere gli stili dei pulsanti con quelli delle
caselle di testo.
A questo punto, occupiamoci del controller, ovvero index.js.
Esso dovrà contenere la definizione
delle callback save, prev e next.
Il salvataggio del modello
corrisponderà ad un caricamento della collezione, che includerà il nuovo
modello insieme a quelli già presenti (funzione save). La
selezione del modello precedente e di quello successivo sarà implementata
con l'incremento o decremento di un indice, che
punterà ad un corrispondente modello della collezione. Una volta selezionato con il metodo .at
di Backbone, il modello viene estratto dalla collezione, e
i suoi attributi vengono usati come valori del modulo di
inserimento dati (funzioni prev e next). Per questi motivi
ci occorreranno anche una collezione ed una variabile indice.
var index = 0;
var books = Alloy.createCollection("book");
// carica la collezione dalla memoria (database)
books.fetch();
La funzione save crea il modello con i valori che sono
stati inseriti nel modulo di inserimento dati, inserisce il
modello nella collezione books, salva il modello e pulisce il
modulo.
function save(e) {
// Crea un modello di tipo 'book'
var book = Alloy.createModel('book', {
title : $.title.value,
author : $.author.value,
isbn : $.isbn.value
});
// aggiungi un modello alla collezione
books.add(book);
// salva il modello
book.save();
index++;
// pulisci la form
$.title.value = "";
$.author.value = "";
$.isbn.value = "";
alert("inserimento completato");
}
Le funzioni prev e next si occupano di aggiornare
l'indice index e di controllare che non oltrepassi i
limiti della collezione.
function prev() {
index--;
if (index = books.length) {
index = books.length - 1;
}
showModel(index);
}
Una volta aggiornato l'indice entrambe le precedenti funzioni invocheranno showModel(index)
,
che estrarrà il modello (puntato dall'indice) dalla collezione e
riempirà i valori del modulo di inserimento dati con gli attributi
title, author ed isbn del modello.
function showModel(index) {
// estrae il modello
var model = books.at(index);
// visualizza il modello nella console
Ti.API.info(JSON.stringify(model));
// mostra i valori nella form
$.title.value = model.get("title") || "";
$.author.value = model.get("author") || "";
$.isbn.value = model.get("isbn") || "";
}
Infine non resta che avviare la view index:
// avvia la view
$.index.open();
La documentazione di Backbone
e Titanium
è fondamentale per comprendere pienamente tutte le possibilità che
offrono i modelli e le collezioni Alloy.
Il codice sorgente degli esempi utilizzati in questo articolo è
disponibile su GitHub.