Web/Mobile/ Progressive
App Development
Chi sono
Filippo Matteo Riggio
CTO @ Kaleidoscope Srl
Full Stack Developer
ECMAscript 6 & Typescript
Super set di JavaScript, contiene funzionalità già proprie di ES6, con la possibilità di aggiungere variabili tipizzate.
Angular 2+
Angular è un framework per lo sviluppo di web app, basato sulla logica a componenti.
Creato in collaborazione tra Google e Microsoft.
Apache Cordova & IonicFramework 3+
Ionic Framework è un framework per la creazione di interfacce mobile/desktop, basato su TS / ng2+. Con l'aiuto di Apache Cordova, andremo a creare un app mobile ibrida.
Progressive Web App?
Una PWA è un applicazione realizzata con moderni standard web, che fornisce una UX simile alle app.
Progressive perchè, se una funzionalià non è fornita dal dispositivo, viene fornita in modo progressivo dalla web app.
Le PWA implementano, a differenza delle app native, i concetti di discoverable e linkable.
Possono lavorare offline attraverso i service workers, essere aggiunte allo schermo dello smartphone, ricevere notifiche push,ecc.
ECMAscript 6 & TypeScript
Variabili in ES6
for ( var i = 0; i < 10; i++ ) {
console.log(i); // 0,1,2...9
}
console.log(i); // 10
for ( let i = 0; i < 10; i++ ) {
console.log(i); // 0,1,2...9
}
console.log(i); // Uncaught Reference Error: i is not defined
let
Con l'uso della parola chiave let, invece di var, possiamo contenere lo scope della variabile al solo contesto.
Classi in ES6
class Rocket {
public landing(location) {
// [...]
}
}
class Falcon extends Rocket {
public constructor() {
super();
this.manufacturer = 'SpaceX';
this.stages = 2;
}
public landing(location) {
console.log('On land');
}
}
class Antares extends Rocket {
public constructor() {
super();
this.manufacturer = 'OrbitalATK';
this.stages = 2;
}
public landing(location) {
console.log('In the ocean');
}
}
Promises in ES6
var greetingPromise = sayHello();
greetingPromise.then(function(greeting) {
console.log(greeting);
}, function(error) {
console.error('Uh-oh, ', error); // ERRORE!
});
Serve per gestire le richieste asincrone, senza utilizzare le callbacks.
Una promise può trovarsi in 3 stati:
- pending: la promise non è ancora stata determinata, perchè la richiesta HTTP è ancora in stato pending.
- fulfilled: la richiesta HTTP è conclusa e la promise ha un valore
- rejected: la richiesta HTTP è fallita e la promise non verrà mai fulfilled.
Arrow Functions
// ES 5
var multiply = function(x, y) {
return x * y;
};
// ES 6
var multiply = (x, y) => { return x * y };
// Un caso con gli array
var missions = [
{ name: 'Mercury', flights: 6 },
{ name: 'Gemini', flights: 3 },
{ name: 'Apollo', flights: 11 },
{ name: 'ASTP', flights: 17 },
];
// ES 5
console.log(
missions.map( function(mission) {
return mission.flights;
});
); // [ 6, 3, 11, 17]
// ES 6
console.log(
missions.map(
mission => mission.flights
)
); // [ 6, 3, 11, 17]
Una nuova modalità per scrivere funzioni, più concise.
Tipi
let num: number;
let str: string;
let bool: boolean;
num = 123;
num = 123.456;
num = '123'; // Errore
str = '123';
str = 123; // Errore
bool = true;
bool = false;
bool = 'false'; // Errore
Con TypeScript, possiamo specificare la tipologia delle veriabili, così da effettuare il type-checking a compile time.
E' inoltre possibile specificare anche degli array con i tipi
let booleanArray: boolean[];
let stringArray: string[];
Tipi speciali e funzioni tipizzate
let someVar: any;
someVar = 123;
someVar = '123';
// null e undefined sono trattati come il tipo any
var str: string;
var num: number;
str = undefined;
num = null;
function sayHello(name: string) : string {
return 'Hello ' + name;
}
:void
// Usiamo il tipo void per specificare che la funzione non deve ritornare nulla
function logMessage(message: string) : void {
console.log(message);
}
Template Strings
let user = {
first_name: 'Filippo',
last_name: 'Riggio'
};
let template = `
<div>
<h1>I tuoi dati</h1>
<p>${ user.first_name } - ${ user.last_name }</p>
</div>
`;
Con ES6 è possibile dichiarare template HTML direttamente in JS.
Per farlo si usano i backticks se il codice HTML è su più righe, o i singoli apici se solo su una riga; mentre con il simbolo ${nome_variabile} possiamo interpolare valori al template.
Approfondimento: La sostituzione viene effettuate con l'algoritmo di distanza minima di Levenshtein:
Angular 2+
Installation
# Install Angular CLI
npm install -g @angular/cli
# Craft new application
ng new my-app
# Serve the app
cd my-app
ng serve --open
Components
import { Component } from '@angular/core';
@Component({
selector: 'my-first-component',
template: `<div>Hello, my name is {{name}}.
<button (click)="sayMyName()">Log my name</button>
</div>`,
});
export class MyComponent {
public constructor() {
this.name = 'Inigo Montoya';
}
public sayMyName = () {
console.log('Hello. My name is ', this.name, '. You killed my father. Prepare to die.0);
}
}
Nel passaggio da Angular 1 alla 2, la decisione è stata di migrare tutto verso una struttura a componenti.
Di seguito come si definisce un componente:
Components
<my-first-component></my-first-component>
Importiamo il modulo "Component" dalla libreria di Angular e usiamo il decoratore @Component.
Il selettore ci fornirà il nostro tag html personalizzato da inserire nell'html.
Dopo il decorator, esporteremo la classe che rappresenta il componente.
Approfondimento: il pattern decorator è uno dei tanti pattern di sviluppo.
Inputs
import { Component, Input } from '@angular/core';
@Component({
selector: 'current-user',
template: '<div>{{ user.name }}</div>',
});
export class UserProfile {
@Input user;
public constructor() {
}
}
Importiamo il modulo "Input" dalla libreria di Angular e usiamo il decoratore @Input all'interno della nostra classe.
Con il decoratore @Input andiamo a definire quali parametri possono essere passati in ingresso al nostro componente.
<current-user [user]="currentUser"></current-user>
Data binding (templates)
// {}: per il RENDERING
<div>
Hello, my name is {{ name }}.
</div>
// []: per il BINDING delle proprietà
<card-header [themeColor]="currentColor"></card-header>
// (): per la GESTIONE EVENTI
<my-component (click)="onUserClick($event)"></my-component>
// [()]: per il DATA BINDING BI-DIREZIONALE
// La variabile this.userName sarà sempre aggiornata tra il componente e il template
<input [(ngModel)]="userName">
// *: per DIRETTIVE PROPRIETARIE DI ANGULAR
<my-component *ngFor="let item of items">
<my-component>
Per la fase di comunicazione tra il codice TS e il template HTML del componente, si usa il binding (collegamento), che può essere eseguito attraverso l'uso di parentesi speciali.
Eventi e Eventi Custom
<button (click)="clicked($event)">Click</button>
@Component(...)
export class MyComponent {
public clicked(event) {
}
}
// CUSTOM EVENTS
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'user-profile',
template: '<div>Hi, my name is </div>'
});
export class UserProfile {
@Output userDataUpdated = new EventEmitter();
public constructor() {
// Update user...
this.userDataUpdated.emit(this.user);
}
}
// <user-profile (userDataUpdated)="userProfileUpdated($event)"></user-profile>
import { Component } from '@angular/core';
import { UserProfile } from './user-profile';
export class SettingdPage {
constructor() {}
public userProfileUpdated(user) {
// .... DO STUFF
}
}
Life Cycle Events
@Component(...)
export class MyComponent {
public ngOnInit() {
// Evento chiamato prima dell'inizializzazione del componente
}
public ngOnDestroy() {
// Evento chiamato prima della distruzione del componente
}
// ALTRI EVENTI
public ngDoCheck() { // Evento chiamato per effettuare una custom change detection }
public ngOnChanges(changes) { ... }
// ....
}
Angular mette a disposione svariati eventi per la gestione del ciclo di vita del componente.
Principalmente per gestire 3 aspetti: creation, rendering e distruzione del componente.
Bootstrap dell'applicazione Angular
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app-component';
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Rispetto alla prima versione di Angular, nella versione 2+ è stato cambiato il modo di dichiarare le dipendente.
Le dipendenze vengono dichiarate solamente nel @NgModule.
Il modulo verrà poi inizializzato attraverso il main.ts.
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app-module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
Pipes
<p>Il compleanno è {{ birthday | date }}</p>
<p>Totale dovuto {{ valore | currency }}</p>
<p>Minuscolo {{ 'test' | lowercase }}</p>
<p>Maiuscolo {{ 'test' | uppercase }}</p>
<p>Guadagno {{ valore | percent }}</p>
Le pipes (o filtri) sono delle funzioni utili per la trasformazione dei valori nei template.
Ne esistono di svariati tipi, legati alla formattazione del testo, alla valuta, ecc.
@ViewChild
import { Component, ViewChild } from '@angular/core';
import { UserProfile } from '../user-profile';
@Component({
template: '<user-profile (click)="update()"></user-profile>',
directives: [ UserProfile ]
})
export class MasterPage {
// Assegniamo il componente che vogliamo recuperare, ad una variabile pubblica con il tipo di variabile
public @ViewChild(UserProfile) userProfile: UserProfile;
public constructor() { }
public update() {
this.userProfile.sendData();
}
}
Con il decoratore @ViewChild possiamo leggere e scrivere i componenti figli.
Per farlo, iniettiamo il componente figlio nel padre come ViewChild.
Web/Mobile/Progressive Web App Development - Part 1
By Filippo Matteo Riggio
Web/Mobile/Progressive Web App Development - Part 1
- 456