AngularJS 1 è, similmente a
Knockout JS, un framework
JavaScript per implementare il pattern
Model-View-View Model (MVVM) lato client, ma non si limita solo a questo, infatti va oltre e permette di gestire intere applicazioni basate su una sola pagina dette
Single Page Application (SPA). In aggiunta, non richiede l'uso di un modello basato su oggetti specifici (observable) come
Knockout JS, quindi è più semplice da gestire.
Per utilizzarlo è necessario avere la libreria
JavaScript AngularJS 1, negli esempi seguenti uso anche il
CSS di
Bootstrap 3 per semplificare il disegno della
UI.
Tutti gli esempi sono basati sulla versione 1 di
AngularJSIn pratica, tramite
Angular, posso decorare l'
html tramite degli attibuti e
agganciarlo al modello
JavaScript in modo tale che ogni modifica fatta al modello si
rifletta sulla pagina
html e viceversa. Ovvero una modifica fatta sulla pagina
html, ad esempio l'iserimento di un valore in una textbox sia direttamente salvato su una variabile del modello
JavaScript. Quello che avviene è un
binding bidirezionale tra il
modello (Model)
JavaScript e la
rappresentazione html (View).
Quello che segue è un semplice esempio che prende in input due numeri e li somma mostrando il risultato a video. Inoltre in caso di risultato negativo, lo evidenzia con uno sfondo rosso.
Questa
app è realizzata con questo codice (
Test 1):
<!DOCTYPE html>
<!-- dichiaro il nome della app da usare nel javascript -->
<html ng-app="sgartApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test 1</title>
<link href="/models/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h2>Test 1 <small>AngularJS 1</small></h2>
</div>
<div class="container">
<!-- inizializzo le variabili n1 e n2 -->
<form class="form-horizontal" ng-init="n1=5;n2=7">
<div class="form-group">
<label class="col-sm-2 control-label">Numero 1</label>
<div class="col-sm-10">
<!-- uso ng-model per fare il binding bidirezionale -->
<input type="number" class="form-control" ng-model="n1">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Numero 2</label>
<div class="col-sm-10">
<input type="number" class="form-control" ng-model="n2">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Totale</label>
<!-- uso ng-class per cambiare il colore di sfondo quando il risultato è negativo -->
<label class="col-sm-10" ng-class="{'bg-danger': n1 + n2 < 0}">
<!-- uso ng-bind per fare il binding unidirezionale, posso usare delle espressioni -->
<span ng-bind="n1 + n2"></span>
</div>
</div>
</form>
</div>
<script src="/models/angular.min.js"></script>
<script type="text/javascript">
(function(){ // richiudo tutto in una enclosure per evitare conflitti di nomi
"use strict";
//inizializzo angular
angular.module("sgartApp", []);
})();
</script>
</body>
</html>
Gli elementi da tenere presente per un
app Angular sono:
- deve esserci un attributo ng-app con il nome dell'applicazione
- deve esserci del codice JavaScript che dichiara e inizializza la app: angular.module('sgartApp', []);
- uso l'attributo ng-init per inizializzare le variabile (vengono create implicitamente da angular delle variabili JavaScript e inizializzate nello scope)
- uso l'attributo ng-model quando devo attivare il binding bidirezionale tra la view e il model (controlli di input)
- uso l'attributo ng-bind quando devo attivare il binding unidirezionale tra il model e la view (solo visualizzazione, posso usare delle espressioni)
- uso l'attributo ng-class per applicare una classe css in base al risultato true/false di una espressione
Usato in questo modo non esprime tutte le potenzialità, l'ideale è avere un
controller in modo da separare il
model dalla
view, quindi il codice diventa (
Test 2):
(function(){ // richiudo tutto in una enclosure per evitare conflitti di nomi
"use strict";
// inizializzo angular
var app = angular.module("sgartApp", []);
// creo un CONTROLLER
// la variabile $scope viene "iniettata" (inject) da angular
app.controller("TestCtrl", function($scope) {
// dichiaro le varibili e le aggancio allo scope
$scope.n1 = 5;
$scope.n2 = 7;
// dichiaro le funzioni e le aggancio allo scope
$scope.somma = function() {
return $scope.n1 + $scope.n2;
};
$scope.isNegative = function(){
return $scope.somma() < 0;
};
});
})();
le variabili che iniziano con dollaro ($) sono variabili di AnguarJS
per utilizzarlo devo dichiarare nella view il controller tramite l'attributo
ng-controller e sotituire le espressioni, che prima erano in linea nell'
html, con le relative funzioni:
<!-- tramite ng-controller dichiaro quale controller deternina lo scope delle variabili -->
<div class="container" ng-controller="TestCtrl">
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">Numero 1</label>
<div class="col-sm-10">
<!-- uso ng-model per fare il binding bidirezionale -->
<input type="number" class="form-control" ng-model="n1">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Numero 2</label>
<div class="col-sm-10">
<input type="number" class="form-control" ng-model="n2">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Totale</label>
<!-- uso ng-class per cambiare il colore di sfondo quando il risultato è negativo richiamando una funzione -->
<label class="col-sm-10" ng-class="{'bg-danger': isNegative()}">
<!-- uso ng-bind per fare il binding unidirezionale -->
<span ng-bind="somma()"></span>
</label>
</div>
</div>
In questo caso le variabili si riferiscno allo scope delimitato dal tag
html su cui ho applicato l'attributo
ng-controller. In caso di più controller annidati serve un meccanismo per identificare la variabili di uno specifico controller rispetto ad un altro, devo assegnare un
alias al controller che userò nel Model.
A questo punto il codice diventa (
Test 3):
(function(){ // richiudo tutto in una enclosure per evitare conflitti di nomi
"use strict";
// inizializzo angular
var app = angular.module("sgartApp", []);
})();
(function(){ //dichiaro un altra enclosure per simulare che esista su un altro file, meglio avere un file per controller
"use strict";
console.log(typeof app); // la variabile app non esiste -> undefined
// se il controller è in un altro file non ho la variabile app riprendo la app tramite angular.module("sgartApp")
angular.module("sgartApp").controller("TestCtrl", TestCtrl); // per leggibilità non dichiaro direttamente la funzione ma solo il nome
// dichiaro le variabili di cui voglio fare l'inject ($scope e $http non è usato in questo caso solo come esempio)
TestCtrl.$inject = ["$scope", "$http"];
function TestCtrl($scope, $http) {
var self = this; // memorizzo l'oggetto controller
// dichiaro le varibili e le aggancio al controller
self.n1 = 5;
self.n2 = 7;
// dichiaro le funioni e le aggancio al controller
self.somma = function() {
return self.n1 + self.n2;
};
self.isNegative = function(){
return self.somma() < 0;
};
}
})();
la principale differenza è che non "aggancio" più le variabili allo
$scope ma direttamente al controller
this.
Questo mi permette di definire un alias nella view (ctrl):
<!-- tramite ng-controller dichiaro il controller
non avendo usato $scope devo dichiarare un alias, ad esempio, 'ctrl' -->
<div class="container" ng-controller="TestCtrl as ctrl">
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">Numero 1</label>
<div class="col-sm-10">
<!-- uso ng-model per fare il binding bidirezionale
avendo un alias le variabili vanno referenziate con l'alias -->
<input type="number" class="form-control" ng-model="ctrl.n1">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Numero 2</label>
<div class="col-sm-10">
<input type="number" class="form-control" ng-model="ctrl.n2">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Totale</label>
<!-- uso ng-class per cambiare il colore di sfondo quando il risultato è negativo richiamando una funzione -->
<label class="col-sm-10" ng-class="{'bg-danger': ctrl.isNegative()}">
<!-- uso ng-bind per fare il binding unidirezionale -->
<span ng-bind="ctrl.somma()"></span>
</label>
</div>
</div>
Questo è solo un esempio che usa un sotto insieme degli attributi disponibili e delle potenzialità del framework
AngulaJS 1.