Roma @ IED
17 e 24 Aprile 2015
ad esempio jQuery e' una libreria, espone la DOM API con astrazioni interfaccia di piu' alto livello, ma non ci fornisce ne suggerisce alcuna struttura particolare riguardo l'organizzazione del nostro codice.
al contrario un Framework come AngularJS, oltre a fornirci delle astrazioni di piu' alto livello, ci suggerisce una determinata organizzazione del nostro codice attraverso degli appositi punti di aggancio.
i template AngularJS si mescolano alla pagina HTML, sfruttando la tolleranza dei browser web circa attributi e tag sconosciuti
<body ng-app>
<h1>{{ "Hello AngularJS" }}</h1>
</body>
Perche' il template possa essere interpretato e' necessario che la pagina abbia caricato correttamente AngularJS, ed in particolare il sottosistema detto AngularJS's HTML compiler o $compile Service
Da un Template Engine come l'AngularJS HTML Compiler, ci aspettiamo le seguenti funzionalita':
L'errato collegamento degli script Javascript relativi ad AngularJS (e/o alla nostra applicazione) potrebbe comportare una totale o non completa interpretazione del template.
Alcuni errori di sintassi potrebbero essere tollarati "silenziosamente".
In molti casi, nella console verra' mostrato un messaggio di errore che dovrebbe aiutarci ad identificare il problema.
Durante il processo di compilazione, l'AngularJS $compile passa attraverso l'$interpolate Service tutti gli attributi e i nodi testo per completare le eventuali espressioni contenute:
<h1>Hello {{ name }}!</h1>
Le espressioni verranno aggiunte alla lista di watch e verranno aggiornate nei cicli di re-rendering (se sono stati segnalati degli aggiornamenti)
ng-app / ng-if / ng-show / ng-repeat ... nel gergo AngularJS sono dette direttive.
Le direttive sono dei componenti Angular che consentono di creare nuovi elementi ed attributi riutilizzabili.
a seconda della particolare definizione utilizzata, la direttiva potra' essere utilizzata attraverso 4 sintassi: come tag, attributo, classe o commento:
<span ng-bind="exp"></span>
<ng-bind></ng-bind>
<span class="ng-bind: exp;"></span>
<!-- directive: ng-bind exp -->
ng-app e' una direttiva che indica ad AngularJS:
ng-if e' una direttiva Angular che include un sub-tree nel DOM generato solo se l'espressione vale true.
ng-show ed ng-hide, al contrario, includono il sub-tree nel DOM generato, ma lo rendono rispettivamente visibile o invisibile.
Mediante ng-repeat e' possibile ripetere un sub-tree per tutti gli elementi di un array risultante da una espressione AngularJS.
Gli elementi DOM che compongono un form HTML hanno un attributo value che potrebbe essere modificato in risposta all'interazione dell'utente con il particolare controllo.
ng-model si assicura che la corrispondente variabile nello scope sia sempre in sincronia con il nuovo valore del controllo, attraverso quello che viene definito two-way Data Binding
La direttiva ng-include consente di includere un template parziale (partial) da un file esterno.
Mediante la direttiva ng-controller indichiamo ad AngularJS quale controller dovra' gestire il sub-tree a cui la direttiva e' applicata.
Le applicazioni AngularJS sono composte da moduli, ogni modulo potra' a sua volta dipendere da altri moduli:
(function () {
var app = angular.module("module-name",
["module-dep1", "module-dep2"]);
...
})();
AngularJS attivera' il modulo dopo essersi assicurato che i moduli da cui dipende sono stati definiti.
I controller sono funzioni costruttore che controlla lo scope associato al DOM a cui e' stato agganciato mediante la direttiva ng-controller.
I controller vengono dichiarati attraverso l'helper angular.Module.controller:
(function () {
...
app.controller("MyController", function() {
this.name = "AngularJS"
});
})();
AngularJS crea per i controller degli scope (ambiente, contesto) all'interno del quale poter definire degli attributi di cui effettuare il binding nei template.
E' possibile accedere allo scope di un controller richiedendone il passaggio nei parametri:
app.controller("MyController", function($scope) {
$scope.isUserActive = true;
});
Le piu' recenti Best Practice per AngularJS prevedono l'assegnazione di un nome al controller:
<div ng-controller="MyController as my">
{{ my.attr }}
</div>
e nel controller assegnare gli attributi di cui fare il binding a this:
app.controller("MyController", function($scope) {
this.attr = "AngularJS Binding";
});
L'istanza named del controller sara' definita nell'oggetto $scope del controller stesso (e.g. my -> $scope.my)
La direttiva ng-src ha il solo scopo di evitare che il browser interpreti il parametro prima della risoluzione dell'eventuale espressione angular contenuta:
<img src="{{ imageUrl }}">
<img ng-src="{{ imageUrl }}">
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="app.js"></script>
</head>
<body>
</body>
</html>
<body ng-app>
<h1> Angular Template </h1>
<ul>
<li ng-show="true">visible item</li>
<li ng-hide="true">hidden item</li>
<li ng-if="false">excluded item</li>
</ul>
</body>
<li>{{ "Hello" + "Angular" }}</li>
<li>{{ 10 + 20 | currency }}</li>
<li>{{ 10 + 20 | currency: "€" }}</li>
<li>{{ "2015-04-17" | date }}</li>
<ul>
<li ng-repeat="item in [1,2,3]">
{{item}}
</li>
</ul>
<ul>
<li><input ng-model="name"></input></li>
<li>My name is {{ name }}</li>
</ul>
<div ng-include="'first-template.html'"></div>
<div ng-include="'second-template.html'"></div>
<body ng-app="ex02">
<div ng-controller="MyController as my">
<h1>Hello {{ my.name }}!</h1>
</div>
</body>
(function() {
var app = angular.module("ex02", []);
app.controller("MyController", MyController);
function MyController() {
this.name = "AngularJS"
}
})();
<body ng-app="ex02">
<div ng-controller="ProductController">
<h1>{{ product.title }}</h1>
<p>{{ product.description }}</p>
<img ng-src="{{ product.image }}"></img>
<dl>
<dt>price</dt>
<dd>{{ product.price }}</dd>
</dl>
</div>
</body>
(function() {
...
function ProductController($scope) {
$scope.product = {
title: "AngularJS Intro",
description: "Ebook description",
image: "https://angularjs.org/img/AngularJS-large.png"
price: 10.99
}
}
})();
Dato che ogni tag <script></script> viene interpretato ed eseguito all'interno del medesimo spazio globale costituito dall'oggetto window, e' nata l'esigenza di utilizzare delle tecniche di isolamento per evitare l'effetto di global object pollution.
La tecnica consiste nell'utilizzare una funzione anonima come contesto in cui isolare le variabili e le funzioni private del modulo:
(function() {
var privateVar = 5;
function privateFn(a, b) {
return a + b;
}
window.publicFn = function(b) {
return privateFn(privateVar, b);
}
})();
Quando dichiariamo una funzione in Javascript, il codice all'interno della funzione ha accesso alle variabili che erano accessibili nel contesto in cui e' stata definita, per questo motivo ogni funzione Javascript e' in realta una Closure:
(function startApp() {
var appName = "MyApp";
window.addEventListener("load", onLoad, false);
function onLoad() {
// appName e' stata catturata ed e'
// raggiungibile dalla funzione onLoad
alert("Hello from " + appName);
}
})();
Un oggetto e' detto First Class Object quando e' possibile passare ad una funzione come parametro o ritornare da una funzione come suo valore di ritorno.
Una funzione che accetta un'altra funzione come parametro o ritorna una funzione come suo valore di ritorno e' detta High Order Function.
In Javascript le funzioni sono Oggetti ed e' possibile passarle come parametri ad altre funzioni (e.g. come callback per gestire un evento, o in generale in high order function come i metodi map o forEach dell'oggetto Array)
var doubledValues = [1,2,3].map(function (item) {
return item * 2;
})
window.addEventListener("resize", function() {
}, false);
function multiplier(a) {
return function(b) {
return a * b;
};
}
var double = multiplier(2);
var doubledValues = [1,2,3].map(double);
il termine Hoisting indica l'implicito spostamento delle dichiarazioni nell'interpretazione del codice sorgente.
In particolare le dichiarazioni di variabili e di funzioni vengono implicitamente spostate in cima al contesto corrente (globale o di funzione):
var i = 0;
while(check(i)) {
var j = calc(i);
}
var i = 0, j;
while(check(i)) {
j = calc(i);
}
var total = sum(4, 5);
function sum(a, b) {
return a + b;
}
function sum(a,b) {
return a + b;
}
var total = sum(4, 5);