Utilizzare i template e le rotte
Continuiamo questa introduzione ad AngularJS partendo dal punto in cui ci eravamo interrotti nella . Ad ora la nostra applicazione è composta da una sola view che mostra la lista dei piloti. Vediamo ora come estendere il nostro progetto introducendo la possibilità di visualizzare i dettaglio del pilota selezionato andando a creare una seconda pagina.
Aggiungere la nuova view direttamente nel codice della pagina HTML non risulta una buona soluzione in quanto complicherebbe la gestione e renderebbe il codice ingestibile al crescere dell’applicazione. Fortunatamente AngularJS mette a disposizione un meccanismo, chiamato partial templates, che permette di definire le view in file separati e gestirle all’interno di uno schema comune chiamato layout template. Nel nostro caso il file HTML su cui abbiamo lavorato sino ad ora diventerà il nostro layout template ed avrà questo aspetto
Moto GP riders
Com’è possibile osservare, il contenuto del tag Un ulteriore modifica riguarda la direttiva La funzione Nella terminologia del framework, un modulo è un oggetto che ha lo scopo di definire le caratteristiche di un’applicazione in termini di configurazione, servizi, controller, direttive e molto altro, incapsulandoli all’interno di un pack riutilizzabile in futuro. Per il nostro progetto configureremo il modulo Tramite il metodo Tramite il metodo La specifica A questo punto è necessario creare due file (list.html e details.html) che conterranno il codice HTML delle relative view. Infine è necessario aggiornare il nostro file controller nel seguente modo: Sostanzialmente abbiamo definito un modulo, denominato controllers, il cui scopo è definire i controller per la nostra applicazione. La creazione avviene utilizzando la funzione dove il primo parametro indica il nome assegnato, mentre il secondo è una funzione all’interno della quale verranno inserite tutte le logiche applicative per gestire le diverse interazioni. Nella definizione del secondo controller, oltre allo scope abbiamo specificato l’oggetto di sistema Il risultato finale è il seguente: Sino ad ora abbiamo prelevato, per semplicità, le informazioni dei piloti da un array JSON definito all’interno del controller. Nella realtà questo raramente accade dal momento che in genere i dati vengono prelevati tramita la comunicazione con un server web. Per poter fare ciò dobbiamo far ricorso ad uno dei service predefiniti di AngularJS: In generale un service è un componente che consente di eseguire delle attività tipiche delle applicazioni web. Il service Vediamo da punto di vista pratico come si traduce quanto è stato appena descritto. Supponiamo che la nostra applicazione preveda una Web API che ci fornisce l’elenco dei dati sui piloti in formato JSON e che tale API sia disponibile all’indirizzo Abbiamo aggiunto una chiamata al metodo Termina qui questo tutorial su AngularJS; è possibile reperire il codice sorgente al seguente indirizzo: https://github.com/yupitz/motoGpRiders/tree/step-http è stato sostituito con un
ng-view
. Questo indica al sistema che il div
ospiterà le view, definite in file HTML esterni. Come sia possibile specificare quale di queste view dovrà essere utilizzata lo vedremo tra breve quando parleremo delle routes.
ng-app
alla quale ora è stato associato il valore motoGpRiders
. Questa dicitura indica ad AngularJS che abbiamo bisogno di effettuare delle configurazioni particolari per la nostra applicazione e che queste verranno eseguite all’interno del modulo motoGpRiders
. Questo viene definito all’interno di un file chiamato app.js
(il nome del file non è vincolante), con il seguente codice:
var module = angular.module('motoGpRiders', []);
angular.module
accetta come primo parametro il nome del modulo il quale sarà visibile all’interno della nostra applicazione (per chi mastica Java, è paragonabile alla definizione di una classe pubblica), mentre il secondo parametro conterrà una lista di stringhe che indicano le dipendenze da altri moduli (una sorta di import).motoGpRiders
in modo tale da visualizzare nel div
marcato con la direttiva ng-view
il corretto partial template:
var module = angular.module('motoGpRiders', [
'ngRoute',
'controllers'
]);
module.config(function ($routeProvider) {
$routeProvider.when('/riders', {
templateUrl: 'list.html',
controller: 'ridersListController'
}),
$routeProvider.when('/riders/:number', {
templateUrl: 'details.html',
controller: 'riderDetailsController'
}),
$routeProvider.otherwise({
redirectTo: '/riders'
})
}
);
config()
possiamo specificare le configurazioni da applicare al nostro modulo. Nel nostro caso vogliamo indicare ad AngularJS come individuare la view corretta da visualizzare. Per fare questo sfruttiamo un meccanismo di routing analogo a quello tipico delle applicazioni server. In sostanza l’obiettivo è quello di creare delle rotte, ovvero mappare degli URL a delle view ricorrendo all’oggetto $routeProvider
(nota: è necessario inserire la dipendenza dal modulo ngRoute
).when()
abbiamo la possibilità di mappare un URL ad un oggetto JSON che definisce il file che contiene il codice HTML del partial template ed il relativo controller. Il metodo otherwise()
consente di specificare la configurazione a cui fare riferimento nel caso non sia stato specificato un URL corretto. Nel nostro caso riportiamo l’applicazione della pagina principale tramite un semplice
redirectTo: '/riders'
:number
all’interno della seconda route rappresenta una parte variabile dell’URL che verrà istanziata dinamicamente e che nel nostro caso corrisponderà al numero del pilota da visualizzare.
In pratica, supponendo che index.html sia la pagina contenente il template layout, in corrispondenza dell’URL index.html#/riders
sarà visualizzata la view con l’elenco dei piloti, mentre a index.html#/riders/n
corrisponderà la view che visualizza il dettaglio del pilota con il numero di gara uguale a n
.
var riders = [
{
name: "Valentino Rossi",
number: 46,
team: "Movistar Yamaha MotoGP",
nation: 'ita',
height: 182,
weight: 65,
city: "Urbino"
},
...
]
var controllerManager = angular.module('controllers', []);
controllerManager.controller('ridersListController', function($scope){
$scope.riders = riders;
});
controllerManager.controller('riderDetailsController', function($scope, $routeParams){
$scope.rider = riders.filter(function(rider){
return rider.number == $routeParams.number;
})[0];
});
controllerManager.controller('ridersListController', function($scope){
...
});
$routeParams
che ci consente di ottenere gli eventuali parametri passati nell’URL di richiesta della partial template. In sintesi, il controller recupera le informazioni sul pilota tramite il numero di gara e crea una variabile rider nello scope corrente. Tale variabile verrà utilizzata nel codice HTML presente in details.html. E’ possibile reperire il codice sorgente di questo passo al seguente indirizzo: https://github.com/yupitz/motoGpRiders/tree/step5Comunicazione via HTTP
$http
.$http
, ad esempio, consente di interagire con il server tramite richieste HTTP mentre $location
permette di gestire gli URL e $window
consente di lavorare con la finestra del browser. Per poter utilizzare i diversi service è necessario dichiarare esplicitamente il service che si intende utilizzare all’interno di una scope.server/api/riders.json
. Per ottenere questi dati dobbiamo effettuare una richiesta HTTP di tipo GET al caricamento dell’applicazione. Possiamo fare questo intervenendo sulla definizione del nostro controller come segue:
var controllerManager = angular.module('controllers', []);
var riders;
module.run(function($http){
$http.get('server/api/riders.json').
success(function(data){
riders=data;
}).
error(function(data, status){
alert("Si è verificato un errore nel caricamento della lista dei piloti.");
});
});
controllerManager.controller ...
run()
del modulo associato alla nostra applicazione che ha il compito di eseguire la funzione passata come parametro al completamento dell’inizializzazione. La funzione passata dichiara di voler utilizzare il service $http
indicandolo come parametro, quindi invoca il metodo get()
per effettuare una richiesta all’API web. In caso di successo la risposta del server viene assegnata alla variabile globale photos altrimenti viene generato un messaggio d’errore. Da notare come AngularJS si faccia carico di decodificare automaticamente la stringa JSON inviata dal server trasformandola in un array di oggetti.