In questa lezione vediamo come permettere alle nostre applicazioni di interagire con un server e di lavorare con API, persistere o aggiornare i dati.
L'esempio di applicazione che stiamo realizzando nel corso di questa guida mostra un elenco di notizie memorizzate nella proprietà newsList
del componente HomePage
, come mostrato dal seguente codice:
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {News} from '../../components/news/news';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
newsList: Array<News>;
constructor(public navCtrl: NavController) {
this.newsList = [
new News("Incubo Brexit...", new Date(2016, ...), ...),
new News("AT&T-Time Warner...", ...),
new News("Cyber-attacco DDOS ...", ...)
];
}
}
L'applicazione nasce a scopo didattico, perciò non ci siamo preoccupati dell'origine dei dati presenti nella proprietà newsList
. Per ora li abbiamo "cablati" all'applicazione per concentrarci meglio su come presentarli all'utente, ma in un'applicazione reale questi dati devono essere acquisiti da un server.
Il servizio Http
Per interagire con una Web API messa a disposizione da un server ricorriamo al servizio Http fornito da Angular 2. Questo servizio ci consente di inviare richieste HTTP al server e di elaborare le risposte in modo che siano fruibili dalla nostra applicazione.
Supponiamo allora di avere a disposizione un server che fornisca un elenco di notizie aggiornato come risposta a una chiamata GET all'indirizzo http://myserver.com/news
, il codice del componente HomePage
diventa analogo a quello mostrato di seguito:
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {News} from '../../components/news/news';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
newsList: Array<News>;
constructor(public navCtrl: NavController, public http: Http) {
this.http.get('http://myserver.com/news')
.map(res => res.json())
.subscribe(data => {
this.newsList = data;
});
}
}
Analizziamo le differenze rispetto al codice precedente per comprendere come abbiamo utilizzato il servizio Http. Innanzitutto notiamo le importazioni in cima al modulo:
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
Il primo import
mette a disposizione del nostro componente il servizio Http mentre il secondo rende accessibile l'operatore map
della libreria Rxjs, che utilizzeremo per elaborare la risposta del server. Mentre la prima importazione può risultare ovvia, la seconda può sembrare un po' strana e richiede un minimo di spiegazione.
Infatti, il servizio Http di Angular 2 utilizza un approccio basato sugli Observable per la gestione di elaborazioni asincrone, come appunto sono le chiamate HTTP. Un Observable è un flusso di dati asincrono (stream) che possiamo gestire tramite operatori specializzati come se fosse un array. L'operatore map
è uno di questi operatori, ma la libreria Rxjs ne mette a disposizione numerosi altri.
C'è da evidenziare che il modello di programmazione basato sugli Observable non è specifico della libreria Rxjs. Esistono anche altre librerie che supportano questo modello di programmazione, anche per linguaggi diversi da TypeScript e JavaScript. Tuttavia Angular 2 sfrutta questa libreria e poiché i dati restituiti dal servizio Http sono degli Observable, anche noi dobbiamo importare dalla stessa libreria gli operatori utilizzati nella nostra applicazione.
Quindi, una volta fatte le dovute importazioni, notiamo la presenza di un nuovo parametro nel costruttore del componente HomePage
:
constructor(public navCtrl: NavController, public http: Http) {...}
La presenza del parametro http
ci consente di avere a disposizione un'istanza del servizio Http sfruttando il meccanismo di dependency injection di Angular. Inoltre, dal momento che il parametro viene dichiarato pubblico, stiamo creando implicitamente una proprietà con lo stesso nome.
Arriviamo infine alla chiamata HTTP vera e propria:
constructor(public navCtrl: NavController, public http: Http) {
this.http.get('http://myserver.com/news')
.map(res => res.json())
.subscribe(data => {
this.newsList = data;
});
}
Come possiamo vedere, abbiamo invocato il metodo get()
del servizio http
passando l'url della Web API che ci fornisce le notizie da mostrare nell'applicazione. Da quanto abbiamo detto prima, l'output di questa invocazione è un Observable su cui applichiamo l'operatore map()
. Questo operatore restituisce un altro Observable derivante dall'esecuzione della funzione specificata come argomento su ciascun risultato che arriva dal server.
Nel caso specifico, otterremo un nuovo Observable composto dalla risposta del server in formato JSON. Di quest'ultimo Observable invochiamo il metodo subscribe()
, ossia ci registriamo per essere avvisati quando arriva la risposta del server già convertita in oggetto. Quando la risposta sarà disponibile, verrà eseguita la funzione passata al metodo subscribe()
, che non fa altro che assegnare i dati inviati dal server alla proprietà newsList
.
Da questo momento in poi tutto rientra nel flusso dell'applicazione che avevamo già avuto modo di illustrare nelle puntate precedenti.