AngularJS – Creare applicazioni single page
Ritorniamo con la nostra guida su Angular. Come promesso nel precedente articolo, dopo aver visto come funziona e come si utilizza Angular, possiamo procedere con la creazione di un’applicazione single-page con il framework di Google.
Nel corso di questo articolo apprenderemo:
- Quali sono i principali moduli di Angular e come importarli
- Come utilizzare il modulo ngRoute
- Come utilizzare i template di Angular
Negli esempi riportati in questo articolo useremo la versione 1.2.9 di Angular.
I moduli Angular
I moduli di Angular possono essere considerati delle applicazioni, ma vengono definiti come oggetti (tramite la funzione angular.module) utilizzando una metodologia dichiarativa.
Questa metodologia permette al modulo di definire configurazioni, servizi, controller, direttive, e molto altro, mettendoli in un pack riutilizzabile anche in futuro.
Abbiamo già visto come creare un modulo nel precedente articolo:
var listaDellaSpesa = angular.module('listApp', []);
Angular mette a disposizione già diversi moduli; in rete è possibile trovarne molti altri creati da terze parti.
Nel caso dei moduli forniti da Angular, possiamo trovare gli script da includere nel nostro progetto su Github, in Google CDN, su code.angularjs.org o tramite Bower.
I principali moduli messi a disposizione da Angular sono:
- ngAnimate: permette di gestire animazioni CSS3 quando cambia la view gestita da Angular (per esempio quando viene aggiunto un elemento facendolo apparire con un effetto)
- ngCookies: wrapper per la gestione dei cookies tramite js
- ngLocale: servizio di localizzazione per diversi componenti di Angular
- ngMock: modulo utilizzato per il test di singole parti di applicazioni
- ngResource: questo modulo ci aiuta a interagire con un WebService con architetture RESTful
- ngRoute: modulo che permette di creare rotte e di associare ad esse direttive e controller
- ngSanitize: parser HTML che pulisce il codice da input insicuri
- ngScenario: utilizzato per effettuare test a intere feature di un’applicazione
- ngTouch: fornisce eventi di tipo touch ed altri helper per i dispositivi touch
Oggi, in questa guida, vedremo come utilizzare ngRoute.
ngRoute: creare le rotte
Supponiamo di voler dividere l’applicazione che abbiamo realizzato nell’articolo precedente in tre pagine:
-
la prima pagina identica a come è attualmente
-
la seconda in cui visualizziamo solo le cose da comprare
-
la terza in cui visualizziamo solo le voci della lista che abbiamo già comprato.
Iniziamo perciò importando il modulo ngRoute nella nostra applicazione (trovate l’esempio completo qui):
<!doctype html> <html ng-app="listApp"> <head> <title>Lista della spesa</title> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script> <script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script> </head> <body> <div ng-controller="ListCtrl"> <ul> <li ng-repeat="elemento in lista"> <input type="checkbox" ng-model="elemento.comprato" /> <span ng-if="!elemento.comprato">{{ elemento.nome }}</span> <span ng-if="elemento.comprato" style="text-decoration:line-through;">{{ elemento.nome }}</span> </li> </ul> <input type='text' id='input_nome'/><button ng-click="aggiungi()">Aggiungi</button> </div> <script type="text/javascript" src=https://ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-route.js'></script> <script type="text/javascript" src='assets/js/main.js'></script> </body> </html>
A questo punto dobbiamo dichiarare la dipendenza, tramite l’array passato come secondo parametro (main.js), utilizzando il nome del modulo:
var listaDellaSpesa = angular.module('listApp', [‘ngRoute’]);
Definiamo a questo punto le rotte tramite l’utilizzo della funzione config del modulo, in questo modo:
listaDellaSpesa.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/index', { templateUrl: 'index' }). when('/todo', { templateUrl: 'todo' }). when('/comprate', { templateUrl: 'comprate', controller: 'comprateCtrl' }). otherwise({ redirectTo: '/index' }); }]);
$routeProvider viene automaticamente passato alla funzione dall’injector, di cui abbiamo già parlato nei precedenti articoli.
Le rotte di Angular funzionano tramite l’utilizzo dell’hash, stiamo quindi andando a definire tre rotte:
- nostrapagina.html#/index
- nostrapagina.html#/todo
- nostrapagina.html#/comprate
La funzione when applica a ognuna di queste rotte un template e un controller.
I template possono essere pagine HTML esterne oppure template definiti direttamente nella stessa pagina (la soluzione che adotteremo in questo esempio) e vengono passati a $routeProvider tramite il parametro templateUrl.
In alternativa, tramite una stringa si può passare direttamente HTML alla funzione when utilizzando il parametro template.
La funzione otherwise ci permette di definire una rotta di default dove l’utente sarà redirezionato nel caso in cui la rotta su cui è posizionato non esista.
Ho definito un controller sulla rotta /comprate per aggiungere una funzione e un bottone che ci permetterà di cancellare tutte le cose che abbiamo già spuntato dall’elenco.
I template
I template in Angular possono essere definiti all’interno del tag:
<script type="text/ng-template" id="NOME_TEMPLATE"></script>
All’interno del template possiamo scrivere codice HTML ed espressioni Angular che verranno valutate.
I template vengono caricati dentro una direttiva ngView:
<div ng-view></div>
Rivediamo perciò il codice HTML della nostra pagina come segue:
<!doctype html> <html ng-app="listApp"> <head> <title>Lista della spesa</title> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script> <script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script> </head> <body> <div ng-controller="ListCtrl"> <a href="#/index">INDEX</a> <a href="#/todo">TODO</a> <a href="#/comprate">COMPRATE</a> <br/> <br/> <div ng-view></div> </div> <script type="text/ng-template" id="index"> INDEX <ul> <li ng-repeat="elemento in lista"> <input type="checkbox" ng-model="elemento.comprato" /> <span ng-if="!elemento.comprato">{{ elemento.nome }}</span> <span ng-if="elemento.comprato" style="text-decoration:line-through;">{{ elemento.nome }}</span> </li> </ul> <input type='text' id='input_nome'/><button ng-click="aggiungi()">Aggiungi</button> </script> <script type="text/ng-template" id="todo"> TODO <ul> <li ng-repeat="elemento in lista" ng-if="!elemento.comprato"> <input type="checkbox" ng-model="elemento.comprato" /> <span ng-if="!elemento.comprato">{{ elemento.nome }}</span> </li> </ul> <input type='text' id='input_nome'/><button ng-click="aggiungi()">Aggiungi</button> </script> <script type="text/ng-template" id="comprate"> COMPRATE <ul> <li ng-repeat="elemento in lista" ng-if="elemento.comprato"> <input type="checkbox" ng-model="elemento.comprato" /> <span ng-if="elemento.comprato" style="text-decoration:line-through;">{{ elemento.nome }}</span> </li> </ul> <button ng-click="cancella()">Cancella tutti gli elementi già comprati</button> </script> <script type="text/javascript" src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-route.js'></script> <script type="text/javascript" src='assets/js/main.js'></script> </body> </html>
Come si può notare il corpo della pagina è di per se vuoto: abbiamo i link che puntano alle diverse view e la direttiva ng-view per visualizzarle, il resto è tutto stato scorporato nei template.
Il primo template, chiamato index, è identico alla pagina principale dell’applicazione del precedente articolo.
Il secondo template, chiamato todo, ci fa vedere solamente i punti ancora da spuntare, filtrando gli elementi solo quando il flag comprato è negativo:
<li ng-repeat="elemento in lista" ng-if="!elemento.comprato">
Lo stesso ragionamento viene applicato in modo inverso in comprate:
<li ng-repeat="elemento in lista" ng-if="!elemento.comprato">
Ho poi aggiunto a questa view un bottone per cancellare tutti gli elementi già comprati:
<button ng-click="cancella()">Cancella tutti gli elementi già comprati</button>
Con la direttiva ng-click verrà chiamata la funzione cancella sullo $scope più vicino: per questa rotta abbiamo definito un controller adibito a questo scopo. Vediamone l’implementazione (file main.js):
listaDellaSpesa.controller('comprateCtrl', ['$scope',function comprateCtrl($scope) { $scope.cancella = function(){ var arrayLength = $scope.$parent.lista.length; for(var i = 0;i < arrayLength;i++){ if($scope.$parent.lista[i].comprato) { $scope.$parent.lista.splice(i,1); } } } }]);
Questo controller si occupa solo di definire la funzione cancella; a sua volta questa funzione controlla tutti gli elementi della lista e cancella quelli che sono segnati come comprati.
Il controller attuale è figlio di ListCtrl, perciò possiamo accedervi tramite $parent e utilizzare la lista contenuta sullo scope padre.
La funzione splice è una funzione nativa in Javascript e permette di rimuovere uno o più elementi da un array. Il primo parametro rappresenta l’indice dell’array da cui iniziare a rimuovere gli elementi, il secondo il numero di elementi da rimuovere.
Conclusioni
Abbiamo visto come creare delle rotte con Angular: questa tecnica ci permette di poter “cambiare pagina” lato client, quindi richiedendo una sola pagina al server.
Questa pratica consente agli sviluppatori di dividere back-end e front-end, anche a livello di risorse, facendo comunicare l’applicazione Angular con il server tramite AJAX.
Possiamo inoltre usufruire del model che viene sincronizzato tra le diverse viste.
E poi, grazie a questo metodo, possiamo sfruttare i vantaggi che troviamo ogni volta che si parla di AngularJS: velocità di sviluppo, riutilizzabilità e metodo di lavoro.
Vedremo nel prossimo articolo come utilizzare le rotte in modo più dinamico.
Alla prossima!
3 commenti
Trackback e pingback
[…] Ritorniamo con la nostra guida su Angular. […]