SlideShare a Scribd company logo
1 of 93
Download to read offline
1 / 92
Bootcamp AngularJS Advanced Class
Tecniche avanzate per padroneggiare il framework
1 / 92
Matteo Ronchi, web architect e sviluppatore full-
stack fin dal 2003 realizza applicazioni web, desktop
e mobile. Si occupa quotidianamente di architetture
web e scalabilità ponendo particolare attenzione a
UX e visual design.
Quando non è impegnato a scrivere codice offre
servizi di consulenza, mentoring e formazione su
angularJS e tecnologie frontend.
Fabio Biondi è un istruttore certificato Adobe con
più di 10 anni di esperienza nello sviluppo di
componenti custom, infografiche e interfacce
interattive cross-platform.
Attualmente si occupa di sviluppo, consulenza e
training su AngularJS, React, CreateJS, D3.js e
Firebase e organizza eventi formativi online.
GLI SPEAKER
2 / 92
AGENDA TECH WEBINAR
1. Introduzione al Bootcamp AngulrJS Advanced Class
2. CUSTOM DIRECTIVES: scope isolation, accesso al DOM e integrazione librerie 3d party
3. Differenze tra SERVICES, FACTORIES e PROVIDERS e quando usarli
4. Come usare al meglio le PROMISES
5. Cosa sono i DECORATORS e quando possono essere utili
3 / 92
A CHI E' RIVOLTO
Agli sviluppatori che già utilizzano AngularJS e che conoscono le principali funzionalità
del framework ma che desidano approfondire alcune tematiche avanzate, fondamentali
per la creazione di codice di qualità e lo sviluppo di componenti riusabili.
4 / 92
REQUISITI
Familiarità nell’utilizzo delle direttive e dei servizi inclusi in AngularJS
E' inoltre adatto a tutti i partecipanti che hanno frequentato il corso Sviluppare applicazioni con
AngularJS organizzato da CodeMotion.
5 / 92
PROGRAMMA DEL BOOTCAMP
6 / 92
Il programma
FUNDAMENTALS
- Models: service, factory, provider, watcher
- Events
- Promises
- Custom Filters (AngularJS 1.3+)
- Custom Validators (AngularJS 1.3+)
7 / 92
Il programma
SVILUPPO DIRETTIVE
- Manipolazione DOM in direttive
- Integrazione librerie 3rd party e tecnologie
- Nested directives: ereditarietà e proprietà require
- Direttive multiple: priority and terminal
- Utilizzo pre and post link functions
- Utilizzo di $compile all’interno di direttive
8 / 92
Il programma
Utilizzo avanzato delle chiamate REST
- $http service
- $http Interceptors
- Integrazione con sessionStorage e localStorage
9 / 92
DIRETTIVE CUSTOM
panoramica
10 / 92
jQuery
Imperative programming:
<button id="myButton">click me</button>
$('#myButton').show();
AngularJS
Declarative programming:
<button ng-show="ctrl.status">click me</button>
this.status = true;
Imperative vs Declarative
11 / 92
Creare componenti riusabili
<gallery data="ctrl.images"></gallery>
<accordion>
<panel title="panel 1">content</panel>
...
</accordion>
<crop img="angular.png" onCrop="ctrl.cropDone($info)"/>
```html
<colorPicker data="ctrl.myData"
onSelect="doIt($color)" />
<chart data="ctrl.myData" ... />
Aggiungere funzionalità a DOM e direttive
<div draggable></button>
<div translate>LABEL_KEY</div>
<div animate="ctrl.aniProps"></div>
<xyz-button icon="icon.png"
type="primary"
size="large"></xyz-button>
Qual è il nostro obiettivo?
12 / 92
Il risultato?
13 / 92
HTML
<nav>
...
</nav>
<div class="slideshow">
...
</div>
<div class="news">
<div class="item">...</div>
<div class="item">...</div>
...
</div>
...
<footer>
...
</footer>
ANGULARJS
<navigation onChange="ctrl.changePage()" />
<slideshow data="ctrl.slideshow" />
<news data="ctrl.news" />
<grid>
<movie-trailer />
<chart data="..." />
<banner id="123" />
</grid>
<footer />
La nostra applicazione è un "collage" di componenti
14 / 92
PROBLEMATICHE COMUNI NELLA CREAZIONE DI DIRETTIVE:
Scope isolation (@, =, &, true e false) e bindToController
Accesso e Manipolazione del Dom
Integrazione librerie esterne
Direttive nidificate: utilizzo di controller e require
Direttive multiple: priority e terminal
link function (pre e post) e compile
utilizzo del servizio $compile
NOTA: gli argomenti evidenziati in verde saranno trattati superficialmente durante questo webinar ed estesi, insieme ai rimanenti,
durante le giornate di formazione "Mastering AngularJS" e "Bootcamp AngularJS Advances Class" organizzati da CodeMotion
15 / 92
Tip & Tricks
per lo sviluppo di direttive / componenti riutilizzabili
16 / 92
1. Isolare lo scope (=)
Utilizzando il simbolo = è possibile passare proprietà alla direttiva abilitando implicitamente il binding
bidirezionale:
<svg-chart title="ctrl.value" />
.directive('svgChart', function () {
return {
scope: {
title: '='
},
template: '<div>{{title}} ... </div>'
}
})
ATTENZIONE:
Ogni modifica effettuata dalla direttiva ai valori delle proprietà "intacherranno" il modello di dati
originale (ad es. se la direttiva modificasse la proprietà 'title')
Non è possibile applicare più di una direttiva con scope isolato allo stesso elemento del DOM
17 / 92
1. DIFFERENTI TIPOLOGIE DI SCOPE ISOLATION
1. @ : il simbolo @ (aka "Text binding") viene utilizzato per passare stringhe alla direttiva e in questo
scenario il binding sarà di tipo unidirezionale (dal padre al figlio e non viceversa). Esempio di utilizzo:
<svg-chart title="{{ctrl.value}}"
2. false (default): la direttiva non crea un nuovo scope e può quindi accedere a tutte le proprietà e metodi
del contesto in cui è definita (ad es. un controller di una view).
Sconsigliato nel caso l'obiettivo sia quello di creare componenti riusabili.
3. true : la direttiva crea un nuovo scope ereditando tutte le proprietà del padre ed eventuali modifiche alle
proprietà non intaccheranno il modello originale
4. & : aka 'method binding', viene utilizzato per invocare funzione esterne alla direttiva
Esempio jsFiddle
Lettura: Mastering the Scope of the Directives in AngularJS
18 / 92
2. Utilizzare il servizio $watch per monitorare le proprietà
<svg-chart title="ctrl.title" data="ctrl.data" />
.directive('svgChart', function () {
return {
scope: {
title: '=',
data: '=',
},
template: '...',
link: function (scope, element, attrs) {
console.log (scope.title);
scope.$watch('data', function(newValue) {
// do something, i.e. redraw chart
});
}
}
}).
Se per qualche motivo non potete isolare la direttiva, potete passare le proprietà alla direttiva
utilizzando gli attributi (attrs). Il tal caso utilizzare $observe al posto di $watch.
19 / 92
3. Accedere al DOM della direttiva (element e link function)
<div resizable />
La link function è l'ultima fase del ciclo di vita di un componente AngularJS ed è il momento in cui lo scope è
accessibile e in cui si può accedere al DOM grazie alla proprietà element.
.directive('resizable', function () {
return {
restrict: 'A',
link: function (scope, element) {
element.resizable();
}
}
}).
element ritorna l'elemento root del template della direttiva in formato jQuery ( anzi jqLite! )
resizable() è un metodo di jQuery reso disponibile dall'inclusione di jQueryUI in index.html
20 / 92
Hai la necessità di accedere alla reference del DOM
e non all'elemento "wrappato" in jQuery??
Utilizza:
element[0]
21 / 92
4. Comunicazione Direttiva -> Controller (&)
<div resizable on-resize="ctrl.doSomething()" />
.controller('MyCtrl', function() {
this.doSomething = function() { /* ... */ };
});
Per invocare una funzione del controller utilizzare & (aka "method" binding)
.directive('resizable', function () {
return {
restrict: 'A',
scope: {
onResize: '&'
},
link: function (scope, elem, attrs) {
elem.resizable();
elem.on('resize', function (evt, ui) {
scope.onResize();
});
}
};
})
22 / 92
TUTTAVIA...
il codice precedente non è completo!
23 / 92
5. Gestire eventi 'non-AngularJS'
<div resizable on-resize="ctrl.doSomething()" />
Se l'evento è generato da una libreria esterna, come nel caso del resize di jQueryUI, è necessario invocare
manualmente il digest di AngularJS utilizzando ad esempio il servizio $applyAsync:
...
elem.resizable();
// Evento resize di jQueryUI resizable plugin
elem.on('resize', function () {
elem.resizable();
scope.$applyAsync(function() {
scope.onResize();
})
});
}
...
$evalAsync, $apply o $timeout sono alternative e/o trick utilizzabili al posto $applyAsync con risultati molti
simili.
24 / 92
ESEMPI
25 / 92
AngularJS / jQueryUI < resizable >
http://jqueryui.com/
26 / 92
INTEGRIAMO JQUERY UI - > Demo
DIPENDENZE CSS
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
DIPENDENZE JAVASCRIPT
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
ESEMPIO DI UTILIZZO
<div resizable />
27 / 92
LA DIRETTIVA <resizable>:
deve applicare il plugin "resizable" di jQuery UI all'elemento HTML in cui è utilizzata
dev'essere configurabile e supportare tutte le opzioni di jQuery UI Resizable
deve invocare una funzione ad ogni evento resize passando i parametri restituiti da jQueryUI
View e Controller:
<div ng-controller="MyCtrl">
<div resizable options="ctrl.options" on-resize="ctrl.onResize($evt, $ui)" />
</div>
.controller('MyCtrl', function MyCtrl() {
this.options = {maxWidth: 400};
this.onResize = function(evt, ui) {
this.w = ui.size.width;
this.h = ui.size.height;
};
});
28 / 92
LA DIRETTIVA < resizable />
<div resizable config="ctrl.config" on-resize="ctrl.onResize($evt, $ui)" />
.directive('resizable', function () {
return {
restrict: 'A',
scope: {
options: '=',
onResize: '&'
},
link: function postLink(scope, elem, attrs) {
elem.resizable(scope.options);
elem.on('resize', function (evt, ui) {
if (scope.onResize) {
scope.$applyAsync(function () {
scope.onResize({ $evt: evt, $ui: ui });
});
}
});
}
};
});
Ad ogni evento resize vengono passati gli oggetti evt e ui ritornati da jQueryUI
29 / 92
AngularJS / GSAP / TweenMax: < tmax-drag >
http://greensock.com/draggable
30 / 92
< tmax-drag > e la proprietà attrs
Questa direttiva rende trascinabile l'elemento HTML su cui è applicato. > Demo
<img src="angular.png" tmax-drag>
<img src="angular.png" tmax-drag
type="x,y"
edge-resistance="0.9"
throw-props="true"
bounds="body">
.directive('tmaxDrag', function () {
return {
restrict: 'A',
link: function (scope, attrs, element) {
Draggable.create(element, { type: attrs.type || "x,y",
edgeResistance: attrs.edgeResistance || 0.75,
bounds: attrs.bounds || null,
throwProps: scope.$eval(attrs.throwProps) || false});
}
}
});
31 / 92
AngularJS / GSAP / TweenMax: < tweener >
http://greensock.com/gsap
32 / 92
AngularJS / GSAP / TweenMax: < tweener > - Demo
Applicare CSS transitions con TweenMax:
<div tweener props="ctrl.values"></div>
.directive('tweener', function () {
return {
restrict: 'EA',
scope: {
props: '=',
speed: '='
},
link: function (scope, element) {
scope.$watch('props', function(newValue) {
if (newValue) {
TweenMax.killTweensOf(element);
TweenMax.to(element,
scope.speed || 0.5,
{
css: scope.props,
ease: Cubic.easeInOut
});
}
}, true);
}
}
});
33 / 92
AngularJS / GSAP / TweenMax: < tmax-knob >
http://greensock.com/draggable
34 / 92
< tmax-knob > - pt.1 - Demo
E' possibile ruotare gli elementi su cui è applicata simulando la creazione di una manopola:
<img tmax-knob src="imgs/knob.png"
width="200" height="200"
options="ctrl.knobOptions"
on-drag="ctrl.onDrag($rotation)"
on-drag-end="ctrl.onDragEnd($rotation)"/>
.directive('tmaxKnob', function () {
return {
restrict: 'A',
scope: {
options: '=',
onDragEnd: '&',
onDrag: '&'
},
link: function (scope, element) {
// Code in next slide
}
}
})
35 / 92
< tmax-knob > - pt.2: utilizzo di angular.extend
...
link: function (scope, element) {
// Draggable default settings
var defaultOptions = {
type: 'rotation',
bounds: {
minRotation:0,
maxRotation:360
},
onDrag : function (){
// 'this.rotation' is available only in this context by TweenMax onDrag event
scope.$applyAsync(function () {
scope.onDrag({$rotation: this.rotation)})
});
},
onDragEnd : function (){...}
}
// Extend default options with custom options
angular.extend(defaultOptions, scope.options);
// Apply Draggable
Draggable.create(element, defaultOptions);
}
...
36 / 92
Applicare + direttive ad un elemento - Demo
<img src="myImg.jpg"
tmax-drag bounds="body"
tweener props="ctrl.props"
box-shadow="24px" box-shadow-color="#222">
37 / 92
DIRETTIVE
Integrazione con HTML5 Canvas e CreateJS
http://createjs.com/
38 / 92
Questa direttiva crea un chart in un tag HTML5 <Canvas>,
utilizzando come modello di dati un array di numeri interi
(espressi in percentuale 0-100)
<percent-chart width="300" height="100"
data="ctrl.data"
color="#FF0000"
padding="5"
on-bar-over="ctrl.doIt($percentage)"
on-bar-out="ctrl.doIt($percentage)"
>
</percent-chart>
> Demo
LA DIRETTIVA <percent-chart>
39 / 92
ESEMPIO DI UTILIZZO
View:
<percent-chart data="ctrl.data" color-bar="#ff0000" width="200" height="140"> </percent-chart>
Controller:
angular.module('myApp')
.controller('AppController', function () {
this.data = [100, 20, 30, 10, 70, 90];
});
40 / 92
UTILIZZARE IL CANVAS NELLE DIRETTIVE - Demo
// Codice per visualizzare un semplice rettangolo nel canvas utilizzando CreateJS
.directive('percentChart', function () {
return {
replace: true, // the directive's root DOM element is now <canvas>
scope: {
data: '=',
colorBar: '@'
},
template: '<canvas></canvas>',
link: function (scope, element) {
var stage = new createjs.Stage( element[0] );
var color = scope.colorBar || '#FF9900';
// Il codice completo sarà presto disponibile su github
bar = new createjs.Graphics();
bar.beginFill(color);
bar.drawRect(0,0,stage.canvas.width, stage.canvas.height);
barShape = new createjs.Shape(bar);
barShape.x = 0; barShape.y = 0;
stage.addChild(barShape);
stage.update();
}
};
});
41 / 92
Tip & Tricks
42 / 92
1. scope ISOLATION e $watch
Direttive e componenti riutilizzabili, come ad esempio un chart, dovrebbero essere implementate con scope
isolato (= e @) L'utilizzo di watcher permette di monitorare eventuali modifiche al modello di dato e avviare
azioni quali il ridisegnato del chart, una chiamata REST e così via.
.directive('percentChart', function () {
return {
//...
scope: {
data: '='
},
link: function (scope, element, attrs) {
//...
scope.$watch('data', function(newVal) {
// Do something: i.e. redraw the chart
});
}
}
}
});
43 / 92
2. UTILIZZARE IL TAG <canvas> COME template
myApp.directive('percentChart', function () {
return {
//...
template: '<canvas></canvas>',
link: function (scope, element, attrs) {
//...
}
}
}
});
Grazie a questo trick, la proprietà element ritornata dalla link function della direttiva corrisponderà
esattamente al nostro <canvas>
44 / 92
tuttavia... : )
45 / 92
3. LA PROPRIETÀ replace
Quando la direttiva viene renderizzata nel DOM, il contenuto del suo template viene inserito all'interno di un
custom tag HTML5 il cui nome corrisponde a quello della direttiva stessa.
In questo scenario element fa riferimento all'elemento "wrapper" e non al canvas.
Con l'opzione replace: true il DOM generato sarà invece il seguente:
element ora corrisponde al nostro elento <canvas>. Obiettivo raggiunto!
46 / 92
4. element[0]
La libreria EaselJS, utilizzata nell'esempio, in fase di inizializzazione richiede tuttavia un riferimento
all'elemento Canvas e non al suo "wrapper" jqLite.
Cosa contiene element ?
element rappresenta una reference jqLite dell'elemento HTML della direttiva, che nel nostro caso è
rappresentato dall'oggetto <canvas>, che sarà invece disponibile in formato RAW utilizzando element[0]
47 / 92
replace è deprecated dalla versione 1.3
Come accedere quindi ai figli di element?
find(): fornito da jqLite ma limitato ai tag name
var elem = element.find('canvas')
var stage = new createjs.Stage(elem[0]);
querySelector o qualunque altra tecnica:
template: '<canvas class="chart" />',
link: function (scope, element) {
var elem = element[0].querySelector(".chart");
var stage = new createjs.Stage(elem); // in questo caso elem non è un elemento jqLite
...
48 / 92
5. HAVE FUN! :)
In questo esempio utilizziamo le Graphics API della libreria EaselJS per disegnare un fantastico rettangolo ;)
link: function (scope, element, attrs) {
var elem = element.find('canvas');
var stage = new createjs.Stage( elem[0] );
var color = scope.colorBar || '#FF9900';
bar = new createjs.Graphics();
bar.beginFill(color);
bar.drawRect(0,0,stage.canvas.width, stage.canvas.height);
barShape = new createjs.Shape(bar);
barShape.x = 0; barShape.y = 0;
stage.addChild(barShape);
stage.update();
// ... insert here your code to generate a custom chart
}
Visualizza l'esercizio completo su direttive custom e integrazione HTML5 Canvas.
49 / 92
ARCHITETTURE IN ANGULARJS
AngularJSAngularJSoffre diversi elementi built-in
a supporto dello sviluppo di un applicazione
50 / 92
ARCHITETTURE IN ANGULARJS
Promises permettono di gestire meglio dinamiche asincrone.
Services|Factories|Providers elementi cardine di qualsiasi architettura realizzata
in AngularJSAngularJS, abbinati alle promises permettono di creare soluzioni eleganti e
mantenibili.
Decorators offrono la possibilità di modificare e/o estendere le API di moduli
importati nell'applicazione.
NOTA: questi argomenti saranno trattati superficialmente durante questo webinar ed estesi, insieme ai rimanenti, durante le giornate di
formazione "Mastering AngularJS" e "Bootcamp AngularJS Advances Class" organizzati da CodeMotion
51 / 92
PROMISES
un approccio migliore alla programmazione asincrona
52 / 92
IN PRINCIPIO ERANO CALLBACK
La realizzazione di un SPA richiede un uso esteso di invocazioni asincrone
per inviare o ricevere dati da un server remoto
53 / 92
JAVASCRIPT CALLBACK
La principale soluzione adottata in Javascript per gestire codice asincrono è l'uso
di callback
getDataFromServer( config, (data) => console.log(data) );
Node.js ha ulteriormente standardizzato questa pratica definendo una firma
consistente per i callback:
getDataFromServer( config, (data) => console.log(err, data) );
() => Arrow function (es2015)
54 / 92
CALLBACK HELL
I callback funzionano benissimo
ma espongono alcuni effetti secondari non sempre desiderabli
55 / 92
JAVASCRIPT CALLBACK
Eccessivo annidamento del codice e contaminazione tra closures differenti.
getDataFromServer(config, function(data) {
invokeMethodB(data, function(dataB) {
invokeMethodC(data, function(dataC) {
invokeMethodD(data, function(dataD) {
console.log(dataD);
});
});
});
});
Difficoltà nel refactoring e nella mantenibilità del codice.
Difficile leggibilità del codice
56 / 92
PER SEMPLIFICARE LA SCRITTURA DI CODICE ASINCRONO
SONO STATE INTRODOTTE LE PROMISES.
57 / 92
Una promise permette di registrare una funzione che verrà invocata quando
l'invocazione asincrona completa o fallisce.
Questo permette a metodi asincroni di restituire in maniera sincrona la promessa
di un valore futuro.
58 / 92
PROMISES IN PRATICA
Una promise può esistere in uno di questi stati:
pending stato iniziale, in attesa di risoluzione
fulfilled quando l'operazione asincrona è stat completata con successo
rejected quando l'operazione asincrona è fallita
59 / 92
PROMISES IN PRATICA
Una promise espone 2 methodi, entrambi accettano una funzione come argomento:
then invoca il proprio handler alla risoluzione dell'azione invocata
catch invoca il proprio handler al fallimento dell'azione invocata
60 / 92
PROMISES IN PRATICA
La funzione handler passata a then o catch riceverà un solo argomento quando
invocata.
// es5
myPromise
.then(function(data) {
console.log(data);
}).catch(function(reason) {
console.error(reason);
});
// es2015
myPromise
.then( data => console.log(data) )
.catch( reason => console.error(reason) );
61 / 92
Uno dei fondamenti delle promises è:
"una promise restituisce sempre una promise"
62 / 92
PROMISES IN PRATICA
Questo permette di creare catene complesse di azioni asincrone mantenendo il codice
pulito e facile da mantenere.
login()
.then( user => loadProfile(user) )
.then( profile => loadAssets(profile) )
.then( assets => cacheAssets(profile) )
.then( profile => updateView(profile) )
.catch( reason => gotoLoginPage(reason) );
L'uso delle promises assieme alle arrow function introdotte con es2015
permette di avere del codice davvero conciso.
63 / 92
PROMISES: GESTIONE DEGLI ERRORI
Un altro elemento chiave è che un singolo catch intercetta errori ed eccezioni di
qualsiasi elemento della catena.
Se desiderate propagare l'eccezione ad un catch successivo dovete semplicemente
risollevarla:
login()
.then( user => loadProfile(user) )
.catch( reason => {
if (reason.type === 'FATAL') {
// DO SOMETHING
} else {
throw reason;
}
} )
.catch( reason => console.error(reason) );
64 / 92
ANGULARJS PROMISES
AngularJS offre supporto alle promises tramite il servizio $q .
Promises Basic 1
Promises Basic 2
Promises Errors
65 / 92
Architetture in AngularJS
Modules, Services, Factories e Providers
66 / 92
ANGULARJS
Offre diversi elementi a supporto della creazione di architetture altamente
scalabili e flessibili
Non impone nessun vincolo sulla definizione dell'architettura di un applicazione
Permette di utilizzare i Pattern e le strategie che più si adeguano ai requisiti di un
progetto
67 / 92
[cit.] Da grandi poteri derivano grandi responsabilità
68 / 92
LA LIBERTÀ HA UN COSTO
La grande flessibilità di AngularJS
è anche il più grande ostacolo per sviluppatori con poca esperienza
nel disegnare architetture scalabili e flessibili
69 / 92
ORGANIZZAZIONE DEL PROGETTO
La struttura che si definisce per il proprio progetto è fondamentale e alla radice di
una buona architettura
AngularJSAngularJSè basato su moduli.
Disegnare la propria applicazione in moduli specializzati è un buon punto di
partenza per creare un applicazione mantenibile.
70 / 92
I MODULI IN ANGULARJS
favoriscono il riutilizzo di componenti
favoriscono lo unit testing
aiutano il lavoro distribuito
permettono lo sviluppo asincrono di funzionalità
aiutano a definire una struttura di cartelle e file facile da comprendere e mantenere
favoriscono la composizione di funzionalità
71 / 92
COS'È UN MODULO
Un modulo è un aggregato di funzionalità predisposte ad un fine comune
Può essere considerato, in termini Object Oriented , come un package
un elemento autosufficiente e facilmente trasportabile
72 / 92
DEFINIZIONE DI UN MODULO
Registrazione di un modulo
angular.module('xyz.code-browser', []);
Registrazione di un modulo con dipendenze da altri moduli
angular.module('xyz.code-browser', ['ui.router', 'ngAnimate']);
Accesso ad un modulo già registrato
angular.module('xyz.code-browser');
73 / 92
Cosa può contenere un modulo
Servizi (service, factory, provider)
View Controllers
Direttive
Costanti
74 / 92
CICLO DI VITA DI UN MODULO
Una volta istanziato ogni modulo esegue una serie di step interni che lo inizializzano.
75 / 92
CICLO DI VITA DI UN MODULO
Alcuni di questi step sono esposti all'esterno e possono essere utilizzati per
configurare l'inizializzazione di un modulo:
Config Phase Eseguita dopo che il modulo ha caricato tutte le proprie dipendenze
ma prima che venga avviato il motore di Dependency Injection
Run Phase Eseguita quando il motore di DI ha soddisfatto tutte le dipendenze e
l'applicazione AngularJS è pronta per operare.
76 / 92
SERVICE, FACTORY E PROVIDER
live demo
quando si approccia AngularJS per la prima volta
è spesso difficile discernere tra i tre servizi
e soprattutto è difficile decidere quale usare a seconda delle situazioni
77 / 92
ALCUNI CONCETTI FONDAMENTALI
I tre servizi sono in realtà un unico servizio
factory e service sono implementazioni differenti di provider
vengono registrati come singleton all'interno dell'applicazione AngularJS
78 / 92
SERVICE
La forma più semplice di provider
79 / 92
SERVICE
Rappresenta l'istanza di una funzione creata usando l'operatore new
angular.module('app',[]).service('myService', MyService);
function MyService() {
this.say = function say(msg) {
return msg;
}
}
AngularJS inizializza il servizio, durante gli step di inizializzazione così:
var myServiceSingleton = new myService();
console.log(myServiceSingleton.say('ciao'));
80 / 92
FACTORY
81 / 92
FACTORY
Viene definita dal valore restituito dall'invocazione della funzione registrata.
angular.module('app',[]).factory('myFactory', MyFactory);
function MyFactory() {
return {
say: function say(msg) {
return msg;
}
};
}
AngularJS inizializza il servizio, durante gli step di inizializzazione così:
var myFactorySingleton = myFactory();
console.log(myFactorySingleton.say('ciao'));
82 / 92
FACTORY
come aggirare il limite del singleton pattern
angular.module('app',[]).factory('myFactory', MyFactory);
function MyService() {
this.say = function say(msg) {
return msg;
}
}
function MyFactory() {
return MyService;
}
var myFactorySingleton = myFactory();
var myServiceInstance = new myFactorySingleton();
console.log(myServiceInstance.say('ciao'));
83 / 92
PROVIDER
L'elemento più potente offerto da AngularJS
84 / 92
Può comportarsi sia come una factory che come un service .
Inoltre permette di esporre una API di configurazione accessibile durante la config
phase di un modulo.
85 / 92
DEFINIRE UN PROVIDER
angular.module('app',[]).provider('myProvider', MyProvider);
function MyProvider() {
var PREFIX = 'AngularJS says: ';
this.setPrefix = function setPrefix(value) {
PREFIX = value;
};
this.$get = function myProviderFactory() {
return return {
say: function say(msg) {
return PREFIX + msg;
}
};
};
}
86 / 92
CONFIGURARE UN PROVIDER
Durante la fase di configurazione di un modulo si può accedere alle API di
personalizzazione esposte dal provider
AngularJS per ogni provider definito rende disponibile, nella fase di config, un
oggetto di configurazione accessibile tramite la sintassi: nomeMioServizio + Provider
angular.module('app',[]).config(
function config(myProviderProvider) {
myProviderProvider.setPrefix('[service said: ] ');
}
)
87 / 92
PROVIDER
AngularJS inizializza il servizio, durante gli step di inizializzazione così:
var myProviderSingleton = myProvider();
console.log(myProviderSingleton.say('ciao'));
88 / 92
DECORATORS
estendere e personalizzare moduli importati
89 / 92
Un decorator intercetta la creazione di un servizio permettendo di modificarne le
API.
Il valore restituito potrebbe essere l'oggetto originale modificato o un oggetto
completamente nuovo.
90 / 92
DECORATORS
Demo 1
Demo 2
angular.module('app')
.service('myService', function myService() {
this.say = function(what) {
return what;
};
})
.config(function config($provide) {
$provide.decorator('myService', function decorateMyService($delegate) {
$delegate._say = $delegate.say;
$delegate.say = function(what = '') {
return what.split('').reverse().join('');
}
return $delegate;
};
});
91 / 92
Matteo Ronchi / Fabio Biondi
unshift.xyz
92 / 92

More Related Content

Similar to Tech Webinar: Advanced AngularJS, tecniche avanzate per padroneggiare il framework

CommitUniversity AngularJSAdvanced Andrea Vallotti
CommitUniversity  AngularJSAdvanced Andrea VallottiCommitUniversity  AngularJSAdvanced Andrea Vallotti
CommitUniversity AngularJSAdvanced Andrea VallottiCommit University
 
Migliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.jsMigliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.jsAndrea Dottor
 
Applicazioni Web ultra-performanti con Vue.js e Delphi
Applicazioni Web ultra-performanti con Vue.js e DelphiApplicazioni Web ultra-performanti con Vue.js e Delphi
Applicazioni Web ultra-performanti con Vue.js e DelphiMarco Breveglieri
 
Introduzione ad angular 7/8
Introduzione ad angular 7/8Introduzione ad angular 7/8
Introduzione ad angular 7/8Valerio Radice
 
E suap - tecnologie client
E suap - tecnologie client E suap - tecnologie client
E suap - tecnologie client Sabino Labarile
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerMatteo Magni
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerMatteo Magni
 
Acadevmy - Angular Overview
Acadevmy - Angular OverviewAcadevmy - Angular Overview
Acadevmy - Angular OverviewFrancesco Sciuti
 
Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8Luca Lusso
 
DDAY2014 - Performance in Drupal 8
DDAY2014 - Performance in Drupal 8DDAY2014 - Performance in Drupal 8
DDAY2014 - Performance in Drupal 8DrupalDay
 
AngularJS On Rails by Daniele Spinosa
AngularJS On Rails by Daniele SpinosaAngularJS On Rails by Daniele Spinosa
AngularJS On Rails by Daniele SpinosaCommit University
 
Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5Pietro Polsinelli
 
Come sviluppare applicazioni cross device con HTML
Come sviluppare applicazioni cross device con HTMLCome sviluppare applicazioni cross device con HTML
Come sviluppare applicazioni cross device con HTMLSinergia Totale
 
GWT vs CSS3
GWT vs CSS3GWT vs CSS3
GWT vs CSS3GWTcon
 

Similar to Tech Webinar: Advanced AngularJS, tecniche avanzate per padroneggiare il framework (20)

AngularJS-Intro
AngularJS-IntroAngularJS-Intro
AngularJS-Intro
 
CommitUniversity AngularJSAdvanced Andrea Vallotti
CommitUniversity  AngularJSAdvanced Andrea VallottiCommitUniversity  AngularJSAdvanced Andrea Vallotti
CommitUniversity AngularJSAdvanced Andrea Vallotti
 
Migliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.jsMigliora il tuo codice con knockout.js
Migliora il tuo codice con knockout.js
 
Corso angular js componenti
Corso angular js componentiCorso angular js componenti
Corso angular js componenti
 
Applicazioni Web ultra-performanti con Vue.js e Delphi
Applicazioni Web ultra-performanti con Vue.js e DelphiApplicazioni Web ultra-performanti con Vue.js e Delphi
Applicazioni Web ultra-performanti con Vue.js e Delphi
 
Introduzione ad angular 7/8
Introduzione ad angular 7/8Introduzione ad angular 7/8
Introduzione ad angular 7/8
 
Corso angular js base
Corso angular js baseCorso angular js base
Corso angular js base
 
jQuery
jQueryjQuery
jQuery
 
E suap - tecnologie client
E suap - tecnologie client E suap - tecnologie client
E suap - tecnologie client
 
react-it.pdf
react-it.pdfreact-it.pdf
react-it.pdf
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesigner
 
jQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesignerjQuery - 1 | WebMaster & WebDesigner
jQuery - 1 | WebMaster & WebDesigner
 
Acadevmy - Angular Overview
Acadevmy - Angular OverviewAcadevmy - Angular Overview
Acadevmy - Angular Overview
 
Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8
 
DDAY2014 - Performance in Drupal 8
DDAY2014 - Performance in Drupal 8DDAY2014 - Performance in Drupal 8
DDAY2014 - Performance in Drupal 8
 
Sviluppare SPA con Vue
Sviluppare SPA con VueSviluppare SPA con Vue
Sviluppare SPA con Vue
 
AngularJS On Rails by Daniele Spinosa
AngularJS On Rails by Daniele SpinosaAngularJS On Rails by Daniele Spinosa
AngularJS On Rails by Daniele Spinosa
 
Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5Matteo Bicocchi - Introducing HTML5
Matteo Bicocchi - Introducing HTML5
 
Come sviluppare applicazioni cross device con HTML
Come sviluppare applicazioni cross device con HTMLCome sviluppare applicazioni cross device con HTML
Come sviluppare applicazioni cross device con HTML
 
GWT vs CSS3
GWT vs CSS3GWT vs CSS3
GWT vs CSS3
 

More from Codemotion

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Codemotion
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyCodemotion
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaCodemotion
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserCodemotion
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Codemotion
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Codemotion
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Codemotion
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 - Codemotion
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Codemotion
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Codemotion
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Codemotion
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Codemotion
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Codemotion
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Codemotion
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Codemotion
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...Codemotion
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Codemotion
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Codemotion
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Codemotion
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Codemotion
 

More from Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Tech Webinar: Advanced AngularJS, tecniche avanzate per padroneggiare il framework

  • 2. Bootcamp AngularJS Advanced Class Tecniche avanzate per padroneggiare il framework 1 / 92
  • 3. Matteo Ronchi, web architect e sviluppatore full- stack fin dal 2003 realizza applicazioni web, desktop e mobile. Si occupa quotidianamente di architetture web e scalabilità ponendo particolare attenzione a UX e visual design. Quando non è impegnato a scrivere codice offre servizi di consulenza, mentoring e formazione su angularJS e tecnologie frontend. Fabio Biondi è un istruttore certificato Adobe con più di 10 anni di esperienza nello sviluppo di componenti custom, infografiche e interfacce interattive cross-platform. Attualmente si occupa di sviluppo, consulenza e training su AngularJS, React, CreateJS, D3.js e Firebase e organizza eventi formativi online. GLI SPEAKER 2 / 92
  • 4. AGENDA TECH WEBINAR 1. Introduzione al Bootcamp AngulrJS Advanced Class 2. CUSTOM DIRECTIVES: scope isolation, accesso al DOM e integrazione librerie 3d party 3. Differenze tra SERVICES, FACTORIES e PROVIDERS e quando usarli 4. Come usare al meglio le PROMISES 5. Cosa sono i DECORATORS e quando possono essere utili 3 / 92
  • 5. A CHI E' RIVOLTO Agli sviluppatori che già utilizzano AngularJS e che conoscono le principali funzionalità del framework ma che desidano approfondire alcune tematiche avanzate, fondamentali per la creazione di codice di qualità e lo sviluppo di componenti riusabili. 4 / 92
  • 6. REQUISITI Familiarità nell’utilizzo delle direttive e dei servizi inclusi in AngularJS E' inoltre adatto a tutti i partecipanti che hanno frequentato il corso Sviluppare applicazioni con AngularJS organizzato da CodeMotion. 5 / 92
  • 8. Il programma FUNDAMENTALS - Models: service, factory, provider, watcher - Events - Promises - Custom Filters (AngularJS 1.3+) - Custom Validators (AngularJS 1.3+) 7 / 92
  • 9. Il programma SVILUPPO DIRETTIVE - Manipolazione DOM in direttive - Integrazione librerie 3rd party e tecnologie - Nested directives: ereditarietà e proprietà require - Direttive multiple: priority and terminal - Utilizzo pre and post link functions - Utilizzo di $compile all’interno di direttive 8 / 92
  • 10. Il programma Utilizzo avanzato delle chiamate REST - $http service - $http Interceptors - Integrazione con sessionStorage e localStorage 9 / 92
  • 12. jQuery Imperative programming: <button id="myButton">click me</button> $('#myButton').show(); AngularJS Declarative programming: <button ng-show="ctrl.status">click me</button> this.status = true; Imperative vs Declarative 11 / 92
  • 13. Creare componenti riusabili <gallery data="ctrl.images"></gallery> <accordion> <panel title="panel 1">content</panel> ... </accordion> <crop img="angular.png" onCrop="ctrl.cropDone($info)"/> ```html <colorPicker data="ctrl.myData" onSelect="doIt($color)" /> <chart data="ctrl.myData" ... /> Aggiungere funzionalità a DOM e direttive <div draggable></button> <div translate>LABEL_KEY</div> <div animate="ctrl.aniProps"></div> <xyz-button icon="icon.png" type="primary" size="large"></xyz-button> Qual è il nostro obiettivo? 12 / 92
  • 15. HTML <nav> ... </nav> <div class="slideshow"> ... </div> <div class="news"> <div class="item">...</div> <div class="item">...</div> ... </div> ... <footer> ... </footer> ANGULARJS <navigation onChange="ctrl.changePage()" /> <slideshow data="ctrl.slideshow" /> <news data="ctrl.news" /> <grid> <movie-trailer /> <chart data="..." /> <banner id="123" /> </grid> <footer /> La nostra applicazione è un "collage" di componenti 14 / 92
  • 16. PROBLEMATICHE COMUNI NELLA CREAZIONE DI DIRETTIVE: Scope isolation (@, =, &, true e false) e bindToController Accesso e Manipolazione del Dom Integrazione librerie esterne Direttive nidificate: utilizzo di controller e require Direttive multiple: priority e terminal link function (pre e post) e compile utilizzo del servizio $compile NOTA: gli argomenti evidenziati in verde saranno trattati superficialmente durante questo webinar ed estesi, insieme ai rimanenti, durante le giornate di formazione "Mastering AngularJS" e "Bootcamp AngularJS Advances Class" organizzati da CodeMotion 15 / 92
  • 17. Tip & Tricks per lo sviluppo di direttive / componenti riutilizzabili 16 / 92
  • 18. 1. Isolare lo scope (=) Utilizzando il simbolo = è possibile passare proprietà alla direttiva abilitando implicitamente il binding bidirezionale: <svg-chart title="ctrl.value" /> .directive('svgChart', function () { return { scope: { title: '=' }, template: '<div>{{title}} ... </div>' } }) ATTENZIONE: Ogni modifica effettuata dalla direttiva ai valori delle proprietà "intacherranno" il modello di dati originale (ad es. se la direttiva modificasse la proprietà 'title') Non è possibile applicare più di una direttiva con scope isolato allo stesso elemento del DOM 17 / 92
  • 19. 1. DIFFERENTI TIPOLOGIE DI SCOPE ISOLATION 1. @ : il simbolo @ (aka "Text binding") viene utilizzato per passare stringhe alla direttiva e in questo scenario il binding sarà di tipo unidirezionale (dal padre al figlio e non viceversa). Esempio di utilizzo: <svg-chart title="{{ctrl.value}}" 2. false (default): la direttiva non crea un nuovo scope e può quindi accedere a tutte le proprietà e metodi del contesto in cui è definita (ad es. un controller di una view). Sconsigliato nel caso l'obiettivo sia quello di creare componenti riusabili. 3. true : la direttiva crea un nuovo scope ereditando tutte le proprietà del padre ed eventuali modifiche alle proprietà non intaccheranno il modello originale 4. & : aka 'method binding', viene utilizzato per invocare funzione esterne alla direttiva Esempio jsFiddle Lettura: Mastering the Scope of the Directives in AngularJS 18 / 92
  • 20. 2. Utilizzare il servizio $watch per monitorare le proprietà <svg-chart title="ctrl.title" data="ctrl.data" /> .directive('svgChart', function () { return { scope: { title: '=', data: '=', }, template: '...', link: function (scope, element, attrs) { console.log (scope.title); scope.$watch('data', function(newValue) { // do something, i.e. redraw chart }); } } }). Se per qualche motivo non potete isolare la direttiva, potete passare le proprietà alla direttiva utilizzando gli attributi (attrs). Il tal caso utilizzare $observe al posto di $watch. 19 / 92
  • 21. 3. Accedere al DOM della direttiva (element e link function) <div resizable /> La link function è l'ultima fase del ciclo di vita di un componente AngularJS ed è il momento in cui lo scope è accessibile e in cui si può accedere al DOM grazie alla proprietà element. .directive('resizable', function () { return { restrict: 'A', link: function (scope, element) { element.resizable(); } } }). element ritorna l'elemento root del template della direttiva in formato jQuery ( anzi jqLite! ) resizable() è un metodo di jQuery reso disponibile dall'inclusione di jQueryUI in index.html 20 / 92
  • 22. Hai la necessità di accedere alla reference del DOM e non all'elemento "wrappato" in jQuery?? Utilizza: element[0] 21 / 92
  • 23. 4. Comunicazione Direttiva -> Controller (&) <div resizable on-resize="ctrl.doSomething()" /> .controller('MyCtrl', function() { this.doSomething = function() { /* ... */ }; }); Per invocare una funzione del controller utilizzare & (aka "method" binding) .directive('resizable', function () { return { restrict: 'A', scope: { onResize: '&' }, link: function (scope, elem, attrs) { elem.resizable(); elem.on('resize', function (evt, ui) { scope.onResize(); }); } }; }) 22 / 92
  • 24. TUTTAVIA... il codice precedente non è completo! 23 / 92
  • 25. 5. Gestire eventi 'non-AngularJS' <div resizable on-resize="ctrl.doSomething()" /> Se l'evento è generato da una libreria esterna, come nel caso del resize di jQueryUI, è necessario invocare manualmente il digest di AngularJS utilizzando ad esempio il servizio $applyAsync: ... elem.resizable(); // Evento resize di jQueryUI resizable plugin elem.on('resize', function () { elem.resizable(); scope.$applyAsync(function() { scope.onResize(); }) }); } ... $evalAsync, $apply o $timeout sono alternative e/o trick utilizzabili al posto $applyAsync con risultati molti simili. 24 / 92
  • 27. AngularJS / jQueryUI < resizable > http://jqueryui.com/ 26 / 92
  • 28. INTEGRIAMO JQUERY UI - > Demo DIPENDENZE CSS <link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css"> DIPENDENZE JAVASCRIPT <script src="//code.jquery.com/jquery-1.10.2.js"></script> <script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script> ESEMPIO DI UTILIZZO <div resizable /> 27 / 92
  • 29. LA DIRETTIVA <resizable>: deve applicare il plugin "resizable" di jQuery UI all'elemento HTML in cui è utilizzata dev'essere configurabile e supportare tutte le opzioni di jQuery UI Resizable deve invocare una funzione ad ogni evento resize passando i parametri restituiti da jQueryUI View e Controller: <div ng-controller="MyCtrl"> <div resizable options="ctrl.options" on-resize="ctrl.onResize($evt, $ui)" /> </div> .controller('MyCtrl', function MyCtrl() { this.options = {maxWidth: 400}; this.onResize = function(evt, ui) { this.w = ui.size.width; this.h = ui.size.height; }; }); 28 / 92
  • 30. LA DIRETTIVA < resizable /> <div resizable config="ctrl.config" on-resize="ctrl.onResize($evt, $ui)" /> .directive('resizable', function () { return { restrict: 'A', scope: { options: '=', onResize: '&' }, link: function postLink(scope, elem, attrs) { elem.resizable(scope.options); elem.on('resize', function (evt, ui) { if (scope.onResize) { scope.$applyAsync(function () { scope.onResize({ $evt: evt, $ui: ui }); }); } }); } }; }); Ad ogni evento resize vengono passati gli oggetti evt e ui ritornati da jQueryUI 29 / 92
  • 31. AngularJS / GSAP / TweenMax: < tmax-drag > http://greensock.com/draggable 30 / 92
  • 32. < tmax-drag > e la proprietà attrs Questa direttiva rende trascinabile l'elemento HTML su cui è applicato. > Demo <img src="angular.png" tmax-drag> <img src="angular.png" tmax-drag type="x,y" edge-resistance="0.9" throw-props="true" bounds="body"> .directive('tmaxDrag', function () { return { restrict: 'A', link: function (scope, attrs, element) { Draggable.create(element, { type: attrs.type || "x,y", edgeResistance: attrs.edgeResistance || 0.75, bounds: attrs.bounds || null, throwProps: scope.$eval(attrs.throwProps) || false}); } } }); 31 / 92
  • 33. AngularJS / GSAP / TweenMax: < tweener > http://greensock.com/gsap 32 / 92
  • 34. AngularJS / GSAP / TweenMax: < tweener > - Demo Applicare CSS transitions con TweenMax: <div tweener props="ctrl.values"></div> .directive('tweener', function () { return { restrict: 'EA', scope: { props: '=', speed: '=' }, link: function (scope, element) { scope.$watch('props', function(newValue) { if (newValue) { TweenMax.killTweensOf(element); TweenMax.to(element, scope.speed || 0.5, { css: scope.props, ease: Cubic.easeInOut }); } }, true); } } }); 33 / 92
  • 35. AngularJS / GSAP / TweenMax: < tmax-knob > http://greensock.com/draggable 34 / 92
  • 36. < tmax-knob > - pt.1 - Demo E' possibile ruotare gli elementi su cui è applicata simulando la creazione di una manopola: <img tmax-knob src="imgs/knob.png" width="200" height="200" options="ctrl.knobOptions" on-drag="ctrl.onDrag($rotation)" on-drag-end="ctrl.onDragEnd($rotation)"/> .directive('tmaxKnob', function () { return { restrict: 'A', scope: { options: '=', onDragEnd: '&', onDrag: '&' }, link: function (scope, element) { // Code in next slide } } }) 35 / 92
  • 37. < tmax-knob > - pt.2: utilizzo di angular.extend ... link: function (scope, element) { // Draggable default settings var defaultOptions = { type: 'rotation', bounds: { minRotation:0, maxRotation:360 }, onDrag : function (){ // 'this.rotation' is available only in this context by TweenMax onDrag event scope.$applyAsync(function () { scope.onDrag({$rotation: this.rotation)}) }); }, onDragEnd : function (){...} } // Extend default options with custom options angular.extend(defaultOptions, scope.options); // Apply Draggable Draggable.create(element, defaultOptions); } ... 36 / 92
  • 38. Applicare + direttive ad un elemento - Demo <img src="myImg.jpg" tmax-drag bounds="body" tweener props="ctrl.props" box-shadow="24px" box-shadow-color="#222"> 37 / 92
  • 39. DIRETTIVE Integrazione con HTML5 Canvas e CreateJS http://createjs.com/ 38 / 92
  • 40. Questa direttiva crea un chart in un tag HTML5 <Canvas>, utilizzando come modello di dati un array di numeri interi (espressi in percentuale 0-100) <percent-chart width="300" height="100" data="ctrl.data" color="#FF0000" padding="5" on-bar-over="ctrl.doIt($percentage)" on-bar-out="ctrl.doIt($percentage)" > </percent-chart> > Demo LA DIRETTIVA <percent-chart> 39 / 92
  • 41. ESEMPIO DI UTILIZZO View: <percent-chart data="ctrl.data" color-bar="#ff0000" width="200" height="140"> </percent-chart> Controller: angular.module('myApp') .controller('AppController', function () { this.data = [100, 20, 30, 10, 70, 90]; }); 40 / 92
  • 42. UTILIZZARE IL CANVAS NELLE DIRETTIVE - Demo // Codice per visualizzare un semplice rettangolo nel canvas utilizzando CreateJS .directive('percentChart', function () { return { replace: true, // the directive's root DOM element is now <canvas> scope: { data: '=', colorBar: '@' }, template: '<canvas></canvas>', link: function (scope, element) { var stage = new createjs.Stage( element[0] ); var color = scope.colorBar || '#FF9900'; // Il codice completo sarà presto disponibile su github bar = new createjs.Graphics(); bar.beginFill(color); bar.drawRect(0,0,stage.canvas.width, stage.canvas.height); barShape = new createjs.Shape(bar); barShape.x = 0; barShape.y = 0; stage.addChild(barShape); stage.update(); } }; }); 41 / 92
  • 44. 1. scope ISOLATION e $watch Direttive e componenti riutilizzabili, come ad esempio un chart, dovrebbero essere implementate con scope isolato (= e @) L'utilizzo di watcher permette di monitorare eventuali modifiche al modello di dato e avviare azioni quali il ridisegnato del chart, una chiamata REST e così via. .directive('percentChart', function () { return { //... scope: { data: '=' }, link: function (scope, element, attrs) { //... scope.$watch('data', function(newVal) { // Do something: i.e. redraw the chart }); } } } }); 43 / 92
  • 45. 2. UTILIZZARE IL TAG <canvas> COME template myApp.directive('percentChart', function () { return { //... template: '<canvas></canvas>', link: function (scope, element, attrs) { //... } } } }); Grazie a questo trick, la proprietà element ritornata dalla link function della direttiva corrisponderà esattamente al nostro <canvas> 44 / 92
  • 47. 3. LA PROPRIETÀ replace Quando la direttiva viene renderizzata nel DOM, il contenuto del suo template viene inserito all'interno di un custom tag HTML5 il cui nome corrisponde a quello della direttiva stessa. In questo scenario element fa riferimento all'elemento "wrapper" e non al canvas. Con l'opzione replace: true il DOM generato sarà invece il seguente: element ora corrisponde al nostro elento <canvas>. Obiettivo raggiunto! 46 / 92
  • 48. 4. element[0] La libreria EaselJS, utilizzata nell'esempio, in fase di inizializzazione richiede tuttavia un riferimento all'elemento Canvas e non al suo "wrapper" jqLite. Cosa contiene element ? element rappresenta una reference jqLite dell'elemento HTML della direttiva, che nel nostro caso è rappresentato dall'oggetto <canvas>, che sarà invece disponibile in formato RAW utilizzando element[0] 47 / 92
  • 49. replace è deprecated dalla versione 1.3 Come accedere quindi ai figli di element? find(): fornito da jqLite ma limitato ai tag name var elem = element.find('canvas') var stage = new createjs.Stage(elem[0]); querySelector o qualunque altra tecnica: template: '<canvas class="chart" />', link: function (scope, element) { var elem = element[0].querySelector(".chart"); var stage = new createjs.Stage(elem); // in questo caso elem non è un elemento jqLite ... 48 / 92
  • 50. 5. HAVE FUN! :) In questo esempio utilizziamo le Graphics API della libreria EaselJS per disegnare un fantastico rettangolo ;) link: function (scope, element, attrs) { var elem = element.find('canvas'); var stage = new createjs.Stage( elem[0] ); var color = scope.colorBar || '#FF9900'; bar = new createjs.Graphics(); bar.beginFill(color); bar.drawRect(0,0,stage.canvas.width, stage.canvas.height); barShape = new createjs.Shape(bar); barShape.x = 0; barShape.y = 0; stage.addChild(barShape); stage.update(); // ... insert here your code to generate a custom chart } Visualizza l'esercizio completo su direttive custom e integrazione HTML5 Canvas. 49 / 92
  • 51. ARCHITETTURE IN ANGULARJS AngularJSAngularJSoffre diversi elementi built-in a supporto dello sviluppo di un applicazione 50 / 92
  • 52. ARCHITETTURE IN ANGULARJS Promises permettono di gestire meglio dinamiche asincrone. Services|Factories|Providers elementi cardine di qualsiasi architettura realizzata in AngularJSAngularJS, abbinati alle promises permettono di creare soluzioni eleganti e mantenibili. Decorators offrono la possibilità di modificare e/o estendere le API di moduli importati nell'applicazione. NOTA: questi argomenti saranno trattati superficialmente durante questo webinar ed estesi, insieme ai rimanenti, durante le giornate di formazione "Mastering AngularJS" e "Bootcamp AngularJS Advances Class" organizzati da CodeMotion 51 / 92
  • 53. PROMISES un approccio migliore alla programmazione asincrona 52 / 92
  • 54. IN PRINCIPIO ERANO CALLBACK La realizzazione di un SPA richiede un uso esteso di invocazioni asincrone per inviare o ricevere dati da un server remoto 53 / 92
  • 55. JAVASCRIPT CALLBACK La principale soluzione adottata in Javascript per gestire codice asincrono è l'uso di callback getDataFromServer( config, (data) => console.log(data) ); Node.js ha ulteriormente standardizzato questa pratica definendo una firma consistente per i callback: getDataFromServer( config, (data) => console.log(err, data) ); () => Arrow function (es2015) 54 / 92
  • 56. CALLBACK HELL I callback funzionano benissimo ma espongono alcuni effetti secondari non sempre desiderabli 55 / 92
  • 57. JAVASCRIPT CALLBACK Eccessivo annidamento del codice e contaminazione tra closures differenti. getDataFromServer(config, function(data) { invokeMethodB(data, function(dataB) { invokeMethodC(data, function(dataC) { invokeMethodD(data, function(dataD) { console.log(dataD); }); }); }); }); Difficoltà nel refactoring e nella mantenibilità del codice. Difficile leggibilità del codice 56 / 92
  • 58. PER SEMPLIFICARE LA SCRITTURA DI CODICE ASINCRONO SONO STATE INTRODOTTE LE PROMISES. 57 / 92
  • 59. Una promise permette di registrare una funzione che verrà invocata quando l'invocazione asincrona completa o fallisce. Questo permette a metodi asincroni di restituire in maniera sincrona la promessa di un valore futuro. 58 / 92
  • 60. PROMISES IN PRATICA Una promise può esistere in uno di questi stati: pending stato iniziale, in attesa di risoluzione fulfilled quando l'operazione asincrona è stat completata con successo rejected quando l'operazione asincrona è fallita 59 / 92
  • 61. PROMISES IN PRATICA Una promise espone 2 methodi, entrambi accettano una funzione come argomento: then invoca il proprio handler alla risoluzione dell'azione invocata catch invoca il proprio handler al fallimento dell'azione invocata 60 / 92
  • 62. PROMISES IN PRATICA La funzione handler passata a then o catch riceverà un solo argomento quando invocata. // es5 myPromise .then(function(data) { console.log(data); }).catch(function(reason) { console.error(reason); }); // es2015 myPromise .then( data => console.log(data) ) .catch( reason => console.error(reason) ); 61 / 92
  • 63. Uno dei fondamenti delle promises è: "una promise restituisce sempre una promise" 62 / 92
  • 64. PROMISES IN PRATICA Questo permette di creare catene complesse di azioni asincrone mantenendo il codice pulito e facile da mantenere. login() .then( user => loadProfile(user) ) .then( profile => loadAssets(profile) ) .then( assets => cacheAssets(profile) ) .then( profile => updateView(profile) ) .catch( reason => gotoLoginPage(reason) ); L'uso delle promises assieme alle arrow function introdotte con es2015 permette di avere del codice davvero conciso. 63 / 92
  • 65. PROMISES: GESTIONE DEGLI ERRORI Un altro elemento chiave è che un singolo catch intercetta errori ed eccezioni di qualsiasi elemento della catena. Se desiderate propagare l'eccezione ad un catch successivo dovete semplicemente risollevarla: login() .then( user => loadProfile(user) ) .catch( reason => { if (reason.type === 'FATAL') { // DO SOMETHING } else { throw reason; } } ) .catch( reason => console.error(reason) ); 64 / 92
  • 66. ANGULARJS PROMISES AngularJS offre supporto alle promises tramite il servizio $q . Promises Basic 1 Promises Basic 2 Promises Errors 65 / 92
  • 67. Architetture in AngularJS Modules, Services, Factories e Providers 66 / 92
  • 68. ANGULARJS Offre diversi elementi a supporto della creazione di architetture altamente scalabili e flessibili Non impone nessun vincolo sulla definizione dell'architettura di un applicazione Permette di utilizzare i Pattern e le strategie che più si adeguano ai requisiti di un progetto 67 / 92
  • 69. [cit.] Da grandi poteri derivano grandi responsabilità 68 / 92
  • 70. LA LIBERTÀ HA UN COSTO La grande flessibilità di AngularJS è anche il più grande ostacolo per sviluppatori con poca esperienza nel disegnare architetture scalabili e flessibili 69 / 92
  • 71. ORGANIZZAZIONE DEL PROGETTO La struttura che si definisce per il proprio progetto è fondamentale e alla radice di una buona architettura AngularJSAngularJSè basato su moduli. Disegnare la propria applicazione in moduli specializzati è un buon punto di partenza per creare un applicazione mantenibile. 70 / 92
  • 72. I MODULI IN ANGULARJS favoriscono il riutilizzo di componenti favoriscono lo unit testing aiutano il lavoro distribuito permettono lo sviluppo asincrono di funzionalità aiutano a definire una struttura di cartelle e file facile da comprendere e mantenere favoriscono la composizione di funzionalità 71 / 92
  • 73. COS'È UN MODULO Un modulo è un aggregato di funzionalità predisposte ad un fine comune Può essere considerato, in termini Object Oriented , come un package un elemento autosufficiente e facilmente trasportabile 72 / 92
  • 74. DEFINIZIONE DI UN MODULO Registrazione di un modulo angular.module('xyz.code-browser', []); Registrazione di un modulo con dipendenze da altri moduli angular.module('xyz.code-browser', ['ui.router', 'ngAnimate']); Accesso ad un modulo già registrato angular.module('xyz.code-browser'); 73 / 92
  • 75. Cosa può contenere un modulo Servizi (service, factory, provider) View Controllers Direttive Costanti 74 / 92
  • 76. CICLO DI VITA DI UN MODULO Una volta istanziato ogni modulo esegue una serie di step interni che lo inizializzano. 75 / 92
  • 77. CICLO DI VITA DI UN MODULO Alcuni di questi step sono esposti all'esterno e possono essere utilizzati per configurare l'inizializzazione di un modulo: Config Phase Eseguita dopo che il modulo ha caricato tutte le proprie dipendenze ma prima che venga avviato il motore di Dependency Injection Run Phase Eseguita quando il motore di DI ha soddisfatto tutte le dipendenze e l'applicazione AngularJS è pronta per operare. 76 / 92
  • 78. SERVICE, FACTORY E PROVIDER live demo quando si approccia AngularJS per la prima volta è spesso difficile discernere tra i tre servizi e soprattutto è difficile decidere quale usare a seconda delle situazioni 77 / 92
  • 79. ALCUNI CONCETTI FONDAMENTALI I tre servizi sono in realtà un unico servizio factory e service sono implementazioni differenti di provider vengono registrati come singleton all'interno dell'applicazione AngularJS 78 / 92
  • 80. SERVICE La forma più semplice di provider 79 / 92
  • 81. SERVICE Rappresenta l'istanza di una funzione creata usando l'operatore new angular.module('app',[]).service('myService', MyService); function MyService() { this.say = function say(msg) { return msg; } } AngularJS inizializza il servizio, durante gli step di inizializzazione così: var myServiceSingleton = new myService(); console.log(myServiceSingleton.say('ciao')); 80 / 92
  • 83. FACTORY Viene definita dal valore restituito dall'invocazione della funzione registrata. angular.module('app',[]).factory('myFactory', MyFactory); function MyFactory() { return { say: function say(msg) { return msg; } }; } AngularJS inizializza il servizio, durante gli step di inizializzazione così: var myFactorySingleton = myFactory(); console.log(myFactorySingleton.say('ciao')); 82 / 92
  • 84. FACTORY come aggirare il limite del singleton pattern angular.module('app',[]).factory('myFactory', MyFactory); function MyService() { this.say = function say(msg) { return msg; } } function MyFactory() { return MyService; } var myFactorySingleton = myFactory(); var myServiceInstance = new myFactorySingleton(); console.log(myServiceInstance.say('ciao')); 83 / 92
  • 85. PROVIDER L'elemento più potente offerto da AngularJS 84 / 92
  • 86. Può comportarsi sia come una factory che come un service . Inoltre permette di esporre una API di configurazione accessibile durante la config phase di un modulo. 85 / 92
  • 87. DEFINIRE UN PROVIDER angular.module('app',[]).provider('myProvider', MyProvider); function MyProvider() { var PREFIX = 'AngularJS says: '; this.setPrefix = function setPrefix(value) { PREFIX = value; }; this.$get = function myProviderFactory() { return return { say: function say(msg) { return PREFIX + msg; } }; }; } 86 / 92
  • 88. CONFIGURARE UN PROVIDER Durante la fase di configurazione di un modulo si può accedere alle API di personalizzazione esposte dal provider AngularJS per ogni provider definito rende disponibile, nella fase di config, un oggetto di configurazione accessibile tramite la sintassi: nomeMioServizio + Provider angular.module('app',[]).config( function config(myProviderProvider) { myProviderProvider.setPrefix('[service said: ] '); } ) 87 / 92
  • 89. PROVIDER AngularJS inizializza il servizio, durante gli step di inizializzazione così: var myProviderSingleton = myProvider(); console.log(myProviderSingleton.say('ciao')); 88 / 92
  • 90. DECORATORS estendere e personalizzare moduli importati 89 / 92
  • 91. Un decorator intercetta la creazione di un servizio permettendo di modificarne le API. Il valore restituito potrebbe essere l'oggetto originale modificato o un oggetto completamente nuovo. 90 / 92
  • 92. DECORATORS Demo 1 Demo 2 angular.module('app') .service('myService', function myService() { this.say = function(what) { return what; }; }) .config(function config($provide) { $provide.decorator('myService', function decorateMyService($delegate) { $delegate._say = $delegate.say; $delegate.say = function(what = '') { return what.split('').reverse().join(''); } return $delegate; }; }); 91 / 92
  • 93. Matteo Ronchi / Fabio Biondi unshift.xyz 92 / 92