
In un articolo precedente, abbiamo introdotto il framework Knockout.js e le sue peculiarità principali, tra cui:
- l’architettura basata sul patten Model-View-ViewModel (MVVM) che permette di separare la logica di presentazione dei dati, il layout e la logica di business dell’applicazione;
- il databinding tramite il quale si può aggiornare automaticamente l’interfaccia utente in base ai dati contenuti nel Model e viceversa;
- gli observables che attuano il databinding in pratica.
In questo post, vedremo il framework al lavoro in un esempio più completo dove il layout sarà impostato con il framework Bootstrap: il codice può essere scaricato in formato zip.
L’interfaccia apparirà come nell’immagine seguente:
e sarà costituita da tre pannelli:
- “Inserimento”: contenente un form per l’introduzione di nuovi dati relativi ad una persona. Per ogni soggetto, saranno registrati un nome, un cognome, l’età, la disponibilità di un’automobile e lo stato civile;
- “Elenco”: un elenco dinamico in cui verranno mostrati gli oggetti inseriti;
- “Statistiche”: una piccola griglia che riporta statistiche sugli inserimenti come il numero di persone registrate e l’età media.
L’interfaccia
L’interfaccia utente, come detto, è stata progettata con Bootstrap, un framework CSS inventato da Twitter, uno degli strumenti più usati nel web design. Questo quanto apparirà nel file HTML:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Gestione del personale</title> <link href="css/bootstrap.min.css" rel="stylesheet"> <link href="css/stile.css" rel="stylesheet"> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <div class="col-md-8 blocco"> <div class="intestazione"> Inserimento </div> <div class="corpo"> <form> <div class="form-group row"> <label class="col-md-2">Cognome</label> <div class="col-md-9"> <input type="text" class="form-control" data-bind="value: cognome"> </div> </div> <div class="form-group row"> <label class="col-md-2">Nome</label> <div class="col-md-9"> <input type="text" class="form-control" data-bind="value: nome"> </div> </div> <div class="form-group row"> <label class="col-md-2">Età</label> <div class="col-md-3"> <input type="text" class="form-control" data-bind="value: eta"> </div> </div> <div class="form-group row"> <label class="col-md-3"><input type="checkbox" data-bind="checked: automunito"> Automunito</label> <div class="col-md-9"> <label>Stato civile</label> <select data-bind="value: statoCivileSelezionato, options: elencoStatoCivile, optionsCaption: '-- Scegliere uno Stato Civile --'"></select> </div> </div> <div class="form-group row"> <div class="text-center buttons"> <button type="submit" class="btn btn-default" data-bind="click: aggiungiPersona">Salva</button> <button type="submit" class="btn btn-default" data-bind="click: pulisciForm">Pulisci</button> </div> </div> </form> </div> <div class="intestazione"> Elenco </div> <div class="corpo"> <div data-bind="foreach: elenco" class="scrollable" > <div class="list-group-item t1"><span data-bind="text: nome"></span> <span data-bind="text: cognome"></span> di anni <span data-bind="text: eta"></span></div> </div> </div> </div> <div class="col-md-4 blocco"> <div class="intestazione"> Statistiche </div> <div> <div class="t1 col-md-6"> Numero inserimenti </div> <div class="t2 col-md-6"> <span data-bind="text: elenco().length">0</span> </div> <div class="t1 col-md-6"> Età media </div> <div class="t2 col-md-6"> <span data-bind="text: etaMedia">0</span> </div> </div> </div> </div> <script src="http://code.jquery.com/jquery.js"></script> <script src="js/bootstrap.min.js"></script> <script type='text/javascript' src="js/knockout-3.4.0.js"></script> <script type='text/javascript'> // codice relativo a Knockout.js </script> </body> </html>
Il codice dell’esempio è qui mostrato integralmente, manca solo la porzione di Javascript che verrà affrontata nel paragrafo seguente.
Per poterlo eseguire, è necessario:
- scaricare Bootstrap o metterlo a disposizione tramite CDN;
- scaricare Knockout.js;
- mettere a disposizione jQuery in qualche maniera.
Tutte le librerie ed i framework necessari verranno introdotti con i necessari tag <script> e, quanto scaricato, sarà organizzato in due cartelle che, nel nostro esempio, si chiamano js per il codice Javascript e css per i fogli di stile. A proposito di quest’ultimo aspetto, abbiamo creato un nostro foglio di stile – collegato al HTML precedente – denominato stile.css il cui contenuto è il seguente:
.blocco { padding: 5px; } .intestazione { padding: 5px; background-color: #cc5200; color: #FFFFFF; font-weight: bold; font-size:16px; border-top-right-radius: 10px; border-top-left-radius: 10px; } .corpo { background-color: #ffa366; padding-top: 5px; padding-right: 5px; padding-left: 5px; margin-bottom: 5px; } .row-bgc { background-color: #ffa366; } .buttons{ padding:8px } .scrollable { height: auto; max-height: 200px; overflow-x: hidden; } .t1 { background-color: #FF6600; padding: 10px; color: #FFFFFF; font-weight: bold; } .t2 { background-color: #FF8533; padding: 10px; color: #FFFFFF; font-weight: bold; }
Gestione dei dati con Knockout.js
Il codice Javascript essenzialmente sarà diviso in tre porzioni:
- creeremo una funzione che servirà per definire gli oggetti di tipo Persona, ognuno dei quali ospiterà i dati inseriti tramite l’utilizzo del form;
- un’altra funzione fornirà il ViewModel che utilizzeremo;
- infine, tramite il metodo dell’oggetto ko agganceremo il nostro ViewModel all’interfaccia utente.
Schematicamente sarà questa la struttura, successivamente approfondiremo il ViewModel nel dettaglio:
function Persona(nome, cognome, eta, automunito, statocivile) { var self = this; self.nome = nome; self.cognome = cognome; self.eta = eta; self.automunito = automunito; self.statocivile = statocivile; } function GestionePersonale() { /* * ViewModel: lo approfondiremo a breve */ } ko.applyBindings(new GestionePersonale());
Nel ViewModel dovremo innanzitutto definire alcune proprietà che saranno rappresentate da observable, quel tipo di oggetti – di cui abbiamo parlato nel precedente articolo – il cui valore viene costantemente sincronizzato con specifici controlli utente dell’interfaccia.
function GestionePersonale() { var self = this; self.elenco = ko.observableArray([]); self.cognome=ko.observable(); self.nome=ko.observable(); self.eta=ko.observable(); self.automunito=ko.observable(); self.elencoStatoCivile=ko.observableArray(['coniugato', 'celibe/nubile', 'separato/divorziato']); self.statoCivileSelezionato=ko.observable(); self.totaleEta=0; self.etaMedia=ko.observable(0); self.quantisono=ko.observable(0); self.aggiungiPersona = function() { self.elenco.push(new Persona(self.nome(),self.cognome(), self.eta(),self.automunito(), self.statoCivileSelezionato())); self.totaleEta+=parseInt(self.eta()); self.etaMedia(self.totaleEta/self.elenco().length); self.pulisciForm(); } self.pulisciForm=function() { self.nome(""); self.cognome(""); self.automunito(false); self.eta(""); self.statoCivileId=0; } }
Si noti, tra l’altro, che ci sono alcuni observable definiti tramite il metodo observableArray che crea un array di oggetti observable. Ciò è utile quando si ha una lista di elementi che deve in qualche maniera essere riprodotta nell’interfaccia.
Qui usiamo due observableArray: uno per contenere i vari oggetti Persona creati che saranno poi visualizzati iterativamente in un elenco, l’altro per alimentare il menu a tendina che mostra gli stati civili selezionabili. Il primo di questi due sarà direttamente trasformato in un elenco HTML tramite il seguente binding di tipo foreach:
<div class="corpo"> <div data-bind="foreach: elenco" class="scrollable" > <div class="list-group-item t1"><span data-bind="text: nome"></span> <span data-bind="text: cognome"></span> di anni <span data-bind="text: eta"> </span> </div> </div> </div>
Un binding di questo tipo ha l’effetto di ripetere tutto il testo HTML, inserito all’interno del tag di cui fa parte, tante volte quante sono gli oggetti presenti nell’observableArray attivando al suo interno gli eventuali binding presenti. I due ulteriori metodi presenti nel ViewModel svolgeranno compiti piuttosto prevedibili:
- aggiungiPersona crea un nuovo oggetto Persona con i dati del form e lo inserisce nell’array di oggetti “osservabili” e, successivamente, aggiorna i dati per le statistiche. La sua attivazione è indotta da un binding di tipo click, collegato al pulsante con etichetta “Salva”;
<button type="submit" class="btn btn-default" data-bind="click: aggiungiPersona">Salva</button>
- pulisciForm pulisce i campi del form dopo un avvenuto inserimento. Esso, oltre che dall’interno del metodo aggiungiPersona può essere invocato tramite binding di tipo click con il pulsante “Pulisci”.
Conclusioni
Sebbene l’esempio non sia dei più complessi mostra in particolare che:
- Knockout.js può entrare a far parte dei vostri progetti integrandosi con tutto ciò che solitamente utilizzate: si veda, ad esempio, la presenza di Bootstrap per l’interfaccia;
- la struttura del codice è piuttosto snella perchè molte parti scontate vengono sempre assolte dal framework.
Knockout.js è un tipico figlio dell’ultima generazione dei prodotti Javascript: utile, rapido, comodo e velocissimo da attivare.
No Responses to “Knockout.js: vediamolo al lavoro con un esempio pratico”