4. Big Picture
L’idea alla base
Components
TemplateDirectives
Services
Injector
Event
binding
Property
binding
5. Components
Proviamo ad individuare i nostri
componenti.
Cosa può e cosa non può essere
un componente?
Keep it simple!
I components sono una key-feature di Angular: possiamo vedere
un’applicazione Angular come una composizione di components
6. Components
Cosa sono
Costruire e comporre
Components rende
gestibili piccoli pezzi
di un’applicazione
Core di Angular
Ogni Component
ha il suo codice
html. Questo
può essere inline
oppure in un file
html a parte.
Template
Ogni
Component può
avere o meno il
suo style.
Style
Avere diversi
Components
consente di dividere
una applicazione
complessa in parti
riusabili.
Presentation logic
Grazie all’utilizzo dei Components una applicazione sarà più aggiornabile e
manutenibile, senza avere tutta la logica scritta in un unico e affollato script.
8. Creare un
Component
La CLI genera una nuova folder
src/app/ciccio-list e i tre files relativi
del nostro componente.
ngOnInit è un hook sul ciclo di vita
del componente. Angular chiama
ngOnInit subito dopo aver istanziato il
componente: è il posto migliore per
inserire della logica di inizializzazione.
Lifecycle
Nel file
ciccio-list.component.ts
troviamo il decoratore
@Component con i
relativi metadata:
- selector
- templateUrl
- styleUrls
@Component
Quando iniziamo
un’applicazione, abbiamo
tutto in un unico
componente
(il root-component).
Prendiamo come esempio la
pagina hacker-news.
Individuiamo il bisogno di generare
un componente ‘lista’ che contenga
e renderizzi i dati contenuti nel file
database.ts
ng generate component ciccio-list
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'hn-ciccio-list',
templateUrl: './ciccio-list.component.html',
styleUrls: ['./ciccio-list.component.css']
})
export class CiccioListComponent implements OnInit {
constructor() { }
ngOnInit() {}
}
9. Creare un
Component
Nel momento in cui si dovesse
creare un Component a mano
bisogna importare il componente
nel app.module.ts e aggiungerlo
nelle declarations
La Angular CLI si occupa
di aggiornare anche il file
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { CiccioListComponent } from './ciccio-list/ciccio-li
st.component';
@NgModule({
declarations: [
AppComponent,
CiccioListComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
11. Data binding
<h3>{{title}}</h3>
Il testo o l’espressione tra le parentesi
corrisponde di solito ad una property del
component e viene calcolato dinamicamente.
Interpolation {{…}}
Il data-binding ci consente di ottenere e settare i valori degli elementi del DOM dinamicamente. Angular si occupa di gestire cio’
che l’utente vede e puo’ fare grazie all’interazione tra l’istanza di classe di un componente e il template HTML che si interfaccia
all’utente.
@Component({
…
})
export class CiccioListComponent
implements OnInit {
description = 'questo è un elemento d
i ciccio-list!';
constructor() {
}
ciccio-list.component.ts
È il meccanismo che consente di coordinare ciò che l’utente vedrà con dati e valori dell’applicazione
<p>
{{description}}
</p>
12. Data binding
Il data-binding ci consente di ottenere e settare i valori degli elementi del DOM dinamicamente. Angular si occupa di gestire cio’
che l’utente vede e puo’ fare grazie all’interazione tra l’istanza di classe di un componente e il template HTML che si interfaccia
all’utente.
@Component({
…
})
export class CiccioListComponent
implements OnInit {
description = 'questo è un elemento d
i ciccio-list!';
sayMyName() {
console.log(this.description);
}
ciccio-list.component.ts
È il meccanismo che consente di coordinare ciò che l’utente vedrà con dati e valori dell’applicazione
(click)=“deleteThing()”
Risponde ad un evento sollevato dal binding
target (un elemento, un componente o una
direttiva). Questa risposta ha quindi un side-
effect.
Template statements
<p (click)="sayMyName()">
{{description}}
</p>
13. Data binding
One-way
Dal dato alla view
{{expression}}
[target]="expression"
bind-target="expression"
One-way
Dalla view al dato
(target)="statement"
on-target="statement"
Two-way
Bidirezionale
[(target)]="expression"
bindon-target="expressio
n"
Angular può gestire questi diversi tipi di data-binding
AKA
Banana in the box
14. Direttive strutturaliLe direttive sono responsabili della manipolazione degli elementi del DOM, quindi del nostro layout definito nel template HMTL. Le
direttive danno forma a questo layout consentendo l’aggiunta, rimozione e manipolazione degli elementi.
La direttiva viene applicata direttamente
ad un elemento host e ai suoi figli.
Elemento Host
01
Le direttive di Angular sono precedute
da un asterisco (*). Nient’altro.
Riconoscibili
02
Angular consente la creazione di
direttive custom che integrino quelle già
disponibili.
Direttive custom
03 *ngFor, *ngIf,
*ngModel….
15. Direttive strutturali
Questa direttiva ci consente di
ciclare su un array e generare i
relativi elementi del DOM
*ngFor
Le direttive sono responsabili della manipolazione degli elementi del DOM, quindi del nostro layout definito nel template
HMTL. Le direttive danno forma a questo layout consentendo l’aggiunta, rimozione e manipolazione degli elementi.
@Component({
…
})
export class CiccioListComponent{
descriptions = [
'sono il primo elemento',
'sono il secondo elemento',
'sono il terzo elemento!'
];
}
ciccio-list.component.ts
Se ad esempio volessimo vedere una lista di description nel nostro ciccio-list Component potremmo usare…
<p>Description:</p>
<ul>
<li (click)="sayMyName(description)"
*ngFor="let description of descriptions">
{{ description }}
</li>
</ul>
16. *ngFor
I nostri elementi vengono visualizzati
correttamente! Se clicchiamo su uno
di essi vedremo in console la stessa
descrizione…
La direttiva *ngFor si è occupata di
generare tanti elementi quanti quelli
presenti nell’array descriptions. Per
ognuno di essi le proprietà di data-
binding sono ancora valide!
Nel DOM
Vediamo cosa è successo dopo aver
applicato la nostra direttiva…
17. È il tuo
turno! 1. Facciamo il clone di questo progetto:
git clone https://bitbucket.org/apuliasoft/hackernews-tutorial.git
2. Per installare tutte le dipendenze necessarie lanciamo il
comando:
npm install
3. Ora digitiamo:
git checkout components-start
In questo modo partiremo tutti con lo stesso progetto.
Creiamo il nostro primo componente del nostro hacker-news
18. È il tuo
turno! • Creiamo un componente link-list.component. Al suo interno:
- importiamo il tipo Link da types
- importiamo il file database.ts come una costante DATABASE
• Visualizziamo tramite un ciclo ngFor i primi due links contenuti in
DATABASE.
• Per ogni elemento del ciclo dobbiamo visualizzare:
- id, description, url, points e pubData
• Leghiamo al pulsante More un comportamento che ci consenta di
cambiare pagina e visualizzare i successivi due link presenti in
DATABASE.
Creiamo il primo componente del nostro hacker-news
20. Interazione tra componenti
Definiamo delle input properties sul
componente figlio: sarà il dato che
verrà passato da padre a figlio.
Grazie al decoratore @Input
comunichiamo ad Angular che questo
componente riceverà un dato da un
altro componente.
Parent-> Child @Input
I dati fluiscono nel tuo component tramite il property biding e fuoriescono grazie all’event-binding
@Component({
…
})
export class CiccioItemComponent {
@Input() description: string;
}
ciccio-item.component.ts
Cosa facciamo quando due componenti hanno bisogno di comunicare tra loro?
21. Interazione tra componenti
Nel componente padre vediamo la
proprietà che è un Array di string.
Parent-> Child @Input
Nota: i decoratori @Input e @Output devono essere importati da @angular/core!
@Component({
…
})
export class CiccioListComponent
implements OnInit {
descriptions: string[];
page: number;
}
ciccio-list.component.ts
Cosa facciamo quando due componenti hanno bisogno di comunicare tra loro?
22. Interazione tra componenti
Nel componente padre (ciccio-
list.component.ts) troviamo innestato il
componente figlio (ciccio-
item.component.ts) all’interno del repeater
*ngFor.
Qui vediamo un binding per ogni iterazione
tra una description del componente padre e
l’istanza del componente figlio.
Parent-> Child @Input
<hn-ciccio-item
*ngFor="let description of descriptio
ns;"
[description]= "description">
</hn-ciccio-item>
ciccio-list.component.html
Cosa facciamo quando due componenti hanno bisogno di comunicare tra loro?
Nota: i decoratori @Input e @Output devono essere importati da @angular/core!
23. Interazione tra componenti
I dati fluiscono nel tuo component tramite il property biding e fuoriescono grazie all’event-binding
@Component({
…
})
export class CiccioItemComponent {
@Input() description: string;
@Output() sayMyName =new EventEmitter
<string>();
date: Date;
}
ciccio-item.component.ts
Cosa facciamo quando due componenti hanno bisogno di comunicare tra loro?
Il componente figlio espone una proprietà
di tipo EventEmitter, che notifica un certo
evento quando avviene qualcosa.
Child->Parent @Output
24. Interazione tra componenti
Nota: i decoratori @Input e @Output devono essere importati da @angular/core!
@Component({
…
})
export class CiccioListComponent
implements OnInit {
descriptions: string[];
page: number;
…
sayMyName(description: string) {
…
}
ciccio-list.component.ts
Cosa facciamo quando due componenti hanno bisogno di comunicare tra loro?
Nel padre abbiamo inoltre il
metodo sayMyName: il
parametro gli sarà passato dal
figlio.
Child->Parent @Output
25. Interazione tra componenti
<hn-ciccio-item
*ngFor="let description of descriptio
ns;"
[description]= "description"
(sayMyName)="sayMyName($event)">
</hn-ciccio-item>
ciccio-list.component.html
Cosa facciamo quando due componenti hanno bisogno di comunicare tra loro?
Bindiamo ad un evento ‘sayMyName’
la chiamata al metodo
corrispondente nel padre.
Child->Parent @Output
Nota: i decoratori @Input e @Output devono essere importati da @angular/core!
26. Event Emitter
Se vogliamo che il nostro child notifichi al
padre l’avvenimento di un evento
dobbiamo utilizzare EventEmitter .
Child->Parent @Output
@Output() sayMyName =new EventEmitter
<string>();
this.sayMyName.emit(this.description
)
ciccio-item.component.html
(sayMyName)="sayMyName($event)«
ciccio-list.component.html
Cosa facciamo quando due componenti hanno bisogno di comunicare tra loro?
Nota: i decoratori @Input e @Output devono essere importati da @angular/core!
Possiamo vedere Event Emitter come un
Observable. Il componente figlio notifica
infatti un evento ai componenti che si sono
registrati a questo evento.
Angular si sottoscrive a questo evento e
chiamerà il metodo sayMyName().
Event Emitter
27. Pipe
Trasformazioni sul display-value direttamete nel codice HTML (senza modificare davvero il valore)
Angular fornisce alcuni pipes come:
DatePipe, UpperCasePipe… pronti
all’uso.
Built-in pipes
Prendono in input un valore e lo
trasformano nell’output desiderato.
Il comportamento del pipe può
essere applicato e replicabile per
tutti i dati necessari.
Possiamo creare i pipes che ci
servono: sono parametrizzabili e si
possono usare in chain (anche con
i pipes built-in).
Custom pipes
28. Pipe
Nel componente abbiamo la
nostra proprietà con il valore
che vogliamo trasformare.
In questo caso new Date()
genera una data nel formato
2018-04-19T12:45:44.360Z
Non è molto leggibile!
Vogliamo trasformarla in
qualcosa che sia comprensibile
immediatamente.
@Component({
…
})
export class CiccioItemComponent {
@Input() description: string;
@Output() sayMyName =new EventEmitter
<string>();
date: new Date();
}
ciccio-item.component.ts
Come si usa
29. Pipe
Il pipe date viene applicato al valore di
description.date, direttamente nelle
parentesi graffe.
Nel html {{value | pipename }}
<p>
{{ description }},
date : {{description.date | date}}
</p>
ciccio-item.component.html
Come si usa
30. Pipe
Una classe Pipe implementa il metodo
transform della classe PipeTransform.
Questo metodo accetta un valore di input
(quello che dovrà essere trasformato) e altri
parametri (in questo caso ad esempio
l’esponente).
Il decoratore @Pipe dice ad Angular che
quello è un Pipe e consente inoltre di definire il
nome del Pipe che sarà utilizzato nella nostra
applicazione.
L’utilizzo di un custom pipe è identico a quello
dei built-in pipes.
Come si crea un custom pipe
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'exponentialStrength'})
export class ExponentialStrengthPipe
implements PipeTransform {
transform(value: number, exponent: string): number {
let exp = parseFloat(exponent);
return Math.pow(value, isNaN(exp) ? 1 : exp);
}
}
Nota: a meno che non utilizzi la Angular CLI, quando crei un custom Pipe devi registrarlo
nelle declarations dell’AppModule!
31. È il tuo
turno! • Creiamo un componente figlio di link-list: link-item.
• All’interno incapsuliamo la logica del singolo item in modo da
essere ripetuto all’interno di una link-list.
• La componente figlio riceverà in input il link
• La componente figlio espone come Output il metodo upvoted
• Colleghiamo un evento upvoted ad ogni link. Il metodo chiamato
dallo scatenarsi di questo evento dovrà incrementare il valore di
points del singolo link.
• Creiamo un pipe di nome moment che utilizzi la libreria
moment.js e sia in grado di restituire il tempo passato dalla
pubblicazione della news al momento della sua visualizzazione.
Suggerimento: utilizzare il metodo fromNow di moment.js
https://momentjs.com/
Aggiungiamo ancora logica e componenti al nostro hacker-news…