Introduzione a AngularJS
AngularJS Γ¨ un framework JavaScript open source sviluppato da Google che estende l'HTML con nuovi attributi e rende le pagine web dinamiche senza riscrivere la struttura. Γ la versione 1.x del framework Angular, ancora ampiamente usata in progetti legacy.
Caratteristica Descrizione
MVC Separa Model, View e Controller
Data Binding Sincronizzazione automatica tra modello e vista
Direttive Estende l'HTML con nuovi attributi e tag
Dependency Injection Gestione automatica delle dipendenze
Testabile Progettato per il testing unitario
β οΈ
Attenzione: AngularJS (v1.x) ha raggiunto la fine del supporto ufficiale nel dicembre 2021. Per nuovi progetti si raccomanda
Angular moderno (v2+). AngularJS rimane importante per manutenere applicazioni esistenti.
Setup: includere AngularJS
HTML β primo esempio AngularJS Provalo tu βΆ
<!DOCTYPE html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
</head>
<body>
<p>Nome: <input type="text" ng-model="nome"></p>
<p>Ciao, {{ nome }}!</p>
</body>
</html>
L'attributo ng-app dice ad AngularJS di controllare quella porzione di pagina. Le doppie graffe {{ }} visualizzano valori del modello. ng-model crea il binding bidirezionale: modifica il campo e il testo si aggiorna istantaneamente.
Espressioni
Le espressioni AngularJS sono scritte tra doppie graffe {{ espressione }}. Possono contenere operatori matematici, stringhe, oggetti e array β ma non strutture di controllo come if o loop.
HTML β espressioni Provalo tu βΆ
<!DOCTYPE html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
</head>
<body>
<!-- Operazioni matematiche -->
<p>5 + 3 = {{ 5 + 3 }}</p>
<p>10 * 4 = {{ 10 * 4 }}</p>
<!-- Stringhe -->
<p>{{ "Ciao" + " " + "Mondo!" }}</p>
<!-- Oggetto -->
<p ng-init="persona = {nome:'Marco', eta:30}">
{{ persona.nome }} ha {{ persona.eta }} anni.
</p>
<!-- Array -->
<p ng-init="corsi=['HTML','CSS','JavaScript']">
Terzo corso: {{ corsi[2] }}
</p>
</body>
</html>
π ng-init inizializza variabili direttamente nel template. Γ comodo per esempi rapidi, ma nella pratica i dati vanno definiti nel Controller.
Moduli
Un modulo AngularJS Γ¨ il contenitore dell'applicazione. Si crea con angular.module() e si collega alla pagina tramite ng-app="nomeModulo".
HTML + JS β creare un modulo Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="miaApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
</head>
<body>
<div ng-controller="MioController">
<h2>{{ messaggio }}</h2>
<p>Versione: {{ versione }}</p>
</div>
<script>
// Crea il modulo
var app = angular.module('miaApp', []);
// Aggiunge un controller al modulo
app.controller('MioController', function($scope) {
$scope.messaggio = 'Benvenuto in AngularJS!';
$scope.versione = '1.8.3';
});
</script>
</body>
</html>
Il secondo parametro di angular.module() Γ¨ un array di dipendenze. Un array vuoto [] significa che il modulo non dipende da altri moduli.
Direttive
Le direttive sono attributi HTML speciali che iniziano con ng-. Estendono l'HTML aggiungendo comportamenti dinamici. AngularJS ne include decine, e puoi crearne di personalizzate.
Direttiva Funzione
ng-appInizializza l'applicazione AngularJS
ng-modelBinding bidirezionale con un campo input
ng-controllerCollega un controller alla vista
ng-repeatRipete un elemento HTML per ogni item di una lista
ng-ifMostra/nasconde un elemento in base a una condizione
ng-show / ng-hideMostra/nasconde (con display) in base a una condizione
ng-clickEsegue codice al click
ng-classAggiunge classi CSS dinamicamente
ng-styleApplica stili inline dinamicamente
ng-initInizializza variabili di scope
HTML β direttive ng-repeat e ng-if Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="miaApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
</head>
<body>
<div ng-controller="ListaCtrl">
<h3>I miei corsi:</h3>
<ul>
<li ng-repeat="corso in corsi">
{{ corso.nome }}
<span ng-if="corso.completato"> β
</span>
<span ng-if="!corso.completato"> π</span>
</li>
</ul>
<p ng-show="mostraTotale">
Totale corsi: {{ corsi.length }}
</p>
<button ng-click="mostraTotale = !mostraTotale">Mostra/Nascondi totale</button>
</div>
<script>
angular.module('miaApp', []).controller('ListaCtrl', function($scope) {
$scope.corsi = [
{ nome: 'HTML', completato: true },
{ nome: 'CSS', completato: true },
{ nome: 'AngularJS', completato: false }
];
$scope.mostraTotale = false;
});
</script>
</body>
</html>
ng-model
ng-model crea il data binding bidirezionale tra un campo di input e una variabile dello scope. Ogni modifica al campo aggiorna istantaneamente il modello, e viceversa.
HTML β ng-model e binding in tempo reale Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="miaApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
input { padding: 8px; margin: 5px 0; border: 1px solid #ccc; border-radius: 4px; width: 100%; }
.anteprima { background: #f0f4ff; padding: 16px; border-radius: 8px; margin-top: 12px; }
</style>
</head>
<body>
<div ng-controller="ModelloCtrl">
<label>Nome:</label>
<input type="text" ng-model="nome" placeholder="Inserisci nome">
<label>Cognome:</label>
<input type="text" ng-model="cognome" placeholder="Inserisci cognome">
<label>EtΓ :</label>
<input type="number" ng-model="eta" placeholder="EtΓ ">
<div class="anteprima">
<strong>Anteprima in tempo reale:</strong><br>
{{ nome }} {{ cognome }}, {{ eta }} anni
</div>
</div>
<script>
angular.module('miaApp', []).controller('ModelloCtrl', function($scope) {
$scope.nome = 'Marco';
$scope.cognome = 'Rossi';
$scope.eta = 30;
});
</script>
</body>
</html>
Data Binding
Il data binding Γ¨ il meccanismo che sincronizza automaticamente il modello (dati JavaScript) con la vista (HTML). AngularJS usa il binding bidirezionale : ogni cambiamento in uno si riflette nell'altro senza codice aggiuntivo.
HTML β calcolatrice con data binding Provalo tu βΆ
<!DOCTYPE html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
input { width: 80px; padding: 8px; font-size: 1.1rem; text-align: center; }
.risultato { font-size: 1.4rem; font-weight: bold; color: #4f46e5; margin-top: 16px; }
</style>
</head>
<body>
<h2>Calcolatrice live</h2>
<input type="number" ng-model="a" ng-init="a=10">
+
<input type="number" ng-model="b" ng-init="b=5">
<div class="risultato">
Risultato: {{ a * 1 + b * 1 }}
</div>
<p>Somma: {{ a * 1 + b * 1 }}</p>
<p>Differenza: {{ a - b }}</p>
<p>Prodotto: {{ a * b }}</p>
<p>Divisione: {{ (b != 0) ? (a / b | number:2) : 'Divisione per zero!' }}</p>
</body>
</html>
Controller
Il controller Γ¨ una funzione JavaScript che gestisce i dati e la logica della vista. Usa $scope per esporre variabili e funzioni all'HTML.
HTML β controller con metodi Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="negozio">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
button { padding: 8px 16px; margin: 4px; cursor: pointer; border: none; border-radius: 4px; }
.aggiungi { background: #4f46e5; color: #fff; }
.rimuovi { background: #ef4444; color: #fff; }
.carrello { background: #f0fdf4; padding: 16px; border-radius: 8px; margin-top: 12px; }
</style>
</head>
<body>
<div ng-controller="NegozioCtrl">
<h2>π Carrello ({{ carrello.length }} prodotti)</h2>
<div ng-repeat="prodotto in prodotti">
{{ prodotto.nome }} β β¬{{ prodotto.prezzo }}
<button class="aggiungi" ng-click="aggiungi(prodotto)">+ Aggiungi</button>
</div>
<div class="carrello">
<strong>Nel carrello:</strong>
<p ng-repeat="item in carrello">{{ item.nome }} β β¬{{ item.prezzo }}</p>
<p ng-if="carrello.length === 0">Carrello vuoto</p>
<strong>Totale: β¬{{ totale() }}</strong>
<br><button class="rimuovi" ng-click="svuota()">Svuota carrello</button>
</div>
</div>
<script>
angular.module('negozio', []).controller('NegozioCtrl', function($scope) {
$scope.prodotti = [
{ nome: 'Laptop', prezzo: 899 },
{ nome: 'Mouse', prezzo: 25 },
{ nome: 'Tastiera', prezzo: 55 }
];
$scope.carrello = [];
$scope.aggiungi = function(p) { $scope.carrello.push(p); };
$scope.svuota = function() { $scope.carrello = []; };
$scope.totale = function() {
return $scope.carrello.reduce(function(sum, p) { return sum + p.prezzo; }, 0);
};
});
</script>
</body>
</html>
Scope
Lo $scope Γ¨ l'oggetto condiviso tra controller e vista. Γ il "ponte" che rende disponibili dati e funzioni all'HTML. Esiste uno scope radice ($rootScope) accessibile da tutta l'applicazione, e scope locali per ogni controller.
HTML β scope padre e figlio Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="scopeApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 16px; }
.padre { border: 2px solid #4f46e5; padding: 16px; border-radius: 8px; }
.figlio { border: 2px solid #0d9488; padding: 12px; border-radius: 8px; margin-top: 12px; }
</style>
</head>
<body>
<div ng-controller="PadreCtrl" class="padre">
<strong>Scope Padre</strong>
<p>Nome padre: {{ nomePadre }}</p>
<div ng-controller="FiglioCtrl" class="figlio">
<strong>Scope Figlio</strong>
<p>Eredita dal padre: {{ nomePadre }}</p>
<p>Proprio del figlio: {{ nomeFiglio }}</p>
</div>
</div>
<script>
angular.module('scopeApp', [])
.controller('PadreCtrl', function($scope) {
$scope.nomePadre = 'Mario';
})
.controller('FiglioCtrl', function($scope) {
$scope.nomeFiglio = 'Luigi';
});
</script>
</body>
</html>
π‘ Lo scope figlio eredita le proprietΓ dello scope padre (prototypal inheritance di JavaScript). Se lo scope figlio modifica una proprietΓ ereditata, crea una copia locale senza modificare il padre.
Filtri
I filtri trasformano i dati prima che vengano mostrati nella vista. Si applicano con il carattere pipe | nelle espressioni o nel codice JS.
Filtro Effetto Esempio
uppercaseTutto maiuscolo {{ testo | uppercase }}
lowercaseTutto minuscolo {{ testo | lowercase }}
currencyFormato valuta {{ prezzo | currency:"β¬" }}
numberDecimali fissi {{ num | number:2 }}
dateFormato data {{ data | date:"dd/MM/yyyy" }}
orderByOrdina array ng-repeat="x in arr | orderBy:'nome'"
filterFiltra array ng-repeat="x in arr | filter:cerca"
limitToLimita elementi ng-repeat="x in arr | limitTo:3"
HTML β ricerca e filtro in tempo reale Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="filtroApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 16px; }
input { padding: 8px; width: 100%; border: 1px solid #ccc; border-radius: 4px; margin-bottom: 12px; }
th { cursor: pointer; background: #4f46e5; color: #fff; padding: 8px; }
td { padding: 6px 8px; border-bottom: 1px solid #eee; }
</style>
</head>
<body>
<div ng-controller="FiltroCtrl">
<input type="text" ng-model="cerca" placeholder="π Cerca prodotto...">
<table>
<tr>
<th ng-click="ordine='nome'">Nome β</th>
<th ng-click="ordine='prezzo'">Prezzo β</th>
</tr>
<tr ng-repeat="p in prodotti | filter:cerca | orderBy:ordine">
<td>{{ p.nome }}</td>
<td>{{ p.prezzo | currency:"β¬" }}</td>
</tr>
</table>
</div>
<script>
angular.module('filtroApp', []).controller('FiltroCtrl', function($scope) {
$scope.ordine = 'nome';
$scope.prodotti = [
{ nome: 'Laptop', prezzo: 899 },
{ nome: 'Tablet', prezzo: 350 },
{ nome: 'Smartphone',prezzo: 599 },
{ nome: 'Monitor', prezzo: 299 },
{ nome: 'Tastiera', prezzo: 55 }
];
});
</script>
</body>
</html>
Tabelle e ng-repeat
ng-repeat Γ¨ la direttiva piΓΉ usata in AngularJS per generare liste e tabelle dinamiche iterando su array di dati.
HTML β tabella dinamica con ng-repeat Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="tabellaApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 16px; }
table { border-collapse: collapse; width: 100%; }
th { background: #1e293b; color: #fff; padding: 10px; }
td { padding: 8px 10px; border-bottom: 1px solid #e2e8f0; }
tr:nth-child(even) { background: #f8fafc; }
tr:hover { background: #e0f2fe; }
.badge { display:inline-block; padding: 2px 8px; border-radius:99px; font-size:.8rem; font-weight:700; }
.si { background:#dcfce7; color:#166534; }
.no { background:#fee2e2; color:#991b1b; }
</style>
</head>
<body>
<div ng-controller="TabellaCtrl">
<h2>Studenti iscritti</h2>
<table>
<tr>
<th>#</th>
<th>Nome</th>
<th>Voto</th>
<th>Promosso</th>
</tr>
<tr ng-repeat="s in studenti">
<td>{{ $index + 1 }}</td>
<td>{{ s.nome }}</td>
<td>{{ s.voto }}</td>
<td>
<span class="badge" ng-class="s.voto >= 6 ? 'si' : 'no'">
{{ s.voto >= 6 ? 'Sì' : 'No' }}
</span>
</td>
</tr>
</table>
</div>
<script>
angular.module('tabellaApp', []).controller('TabellaCtrl', function($scope) {
$scope.studenti = [
{ nome: 'Alice', voto: 9 },
{ nome: 'Marco', voto: 5 },
{ nome: 'Sofia', voto: 8 },
{ nome: 'Luca', voto: 4 },
{ nome: 'Giulia', voto: 7 }
];
});
</script>
</body>
</html>
π‘ Variabili speciali in ng-repeat: $index (indice corrente), $first, $last, $even, $odd (booleani).
Select
AngularJS semplifica la creazione di menu select dinamici con ng-options, che genera le opzioni da un array.
HTML β select con ng-options Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="selectApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; }
select { padding: 8px; font-size: 1rem; border-radius: 4px; width: 100%; margin: 8px 0; }
.card { background: #f0f4ff; padding: 16px; border-radius: 8px; margin-top: 12px; }
</style>
</head>
<body>
<div ng-controller="SelectCtrl">
<label>Scegli un corso:</label>
<select ng-model="corsoScelto"
ng-options="c.nome for c in corsi">
<option value="">-- Seleziona --</option>
</select>
<div class="card" ng-if="corsoScelto">
<h3>{{ corsoScelto.nome }}</h3>
<p>Durata: {{ corsoScelto.ore }} ore</p>
<p>DifficoltΓ : {{ corsoScelto.livello }}</p>
</div>
</div>
<script>
angular.module('selectApp', []).controller('SelectCtrl', function($scope) {
$scope.corsi = [
{ nome: 'HTML & CSS', ore: 20, livello: 'Principiante' },
{ nome: 'JavaScript', ore: 40, livello: 'Intermedio' },
{ nome: 'AngularJS', ore: 35, livello: 'Intermedio' },
{ nome: 'Node.js', ore: 30, livello: 'Avanzato' }
];
$scope.corsoScelto = null;
});
</script>
</body>
</html>
Servizi
I servizi AngularJS sono oggetti singleton riutilizzabili tra i controller. AngularJS include servizi predefiniti (come $http, $timeout, $interval) e permette di crearne di personalizzati.
HTML β $timeout e $interval Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="servizioApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; }
.orologio { font-size: 2.5rem; font-weight: bold; color: #4f46e5; }
button { padding: 8px 16px; margin: 6px 4px; cursor: pointer; border-radius: 4px; border: none; background: #4f46e5; color: #fff; }
</style>
</head>
<body>
<div ng-controller="ServizioCtrl">
<h2>β± Orologio live</h2>
<div class="orologio">{{ ora }}</div>
<button ng-click="avvia()">βΆ Avvia</button>
<button ng-click="ferma()">βΉ Ferma</button>
<p>Contatore clic sul Avvia: {{ clic }}</p>
</div>
<script>
angular.module('servizioApp', [])
.controller('ServizioCtrl', function($scope, $interval, $filter) {
var timer;
$scope.clic = 0;
function aggiorna() {
$scope.ora = $filter('date')(new Date(), 'HH:mm:ss');
}
aggiorna();
$scope.avvia = function() {
if (!timer) {
$scope.clic++;
timer = $interval(aggiorna, 1000);
}
};
$scope.ferma = function() {
if (timer) { $interval.cancel(timer); timer = null; }
};
});
</script>
</body>
</html>
Servizio personalizzato con factory
JS β factory personalizzata Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="factoryApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style> body { font-family: Arial; padding: 20px; } </style>
</head>
<body>
<div ng-controller="CalcoloCtrl">
<h2>IVA Calculator</h2>
Prezzo netto: <input type="number" ng-model="netto" ng-init="netto=100">
<p>IVA (22%): β¬{{ iva.calcola(netto) | number:2 }}</p>
<p>Totale: β¬{{ iva.totale(netto) | number:2 }}</p>
</div>
<script>
var app = angular.module('factoryApp', []);
// Factory personalizzata
app.factory('iva', function() {
return {
calcola: function(n) { return n * 0.22; },
totale: function(n) { return n * 1.22; }
};
});
// Controller che usa la factory
app.controller('CalcoloCtrl', function($scope, iva) {
$scope.iva = iva;
$scope.netto = 100;
});
</script>
</body>
</html>
$http
Il servizio $http esegue richieste HTTP (AJAX) verso API esterne o file JSON locali. Restituisce una promise con i metodi .then() e .catch().
HTML β $http GET da API pubblica Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="httpApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; }
.post { border: 1px solid #e2e8f0; padding: 12px; border-radius: 8px; margin: 8px 0; }
.post h4 { margin: 0 0 6px; color: #4f46e5; text-transform: capitalize; }
.caricamento { color: #64748b; font-style: italic; }
button { padding: 8px 16px; background: #4f46e5; color: #fff; border: none; border-radius: 4px; cursor: pointer; }
</style>
</head>
<body>
<div ng-controller="HttpCtrl">
<h2>Post da JSONPlaceholder API</h2>
<button ng-click="carica()">π₯ Carica post</button>
<p class="caricamento" ng-if="caricamento">Caricamento in corso...</p>
<p ng-if="errore" style="color:red">Errore: {{ errore }}</p>
<div class="post" ng-repeat="p in posts | limitTo:5">
<h4>{{ p.title }}</h4>
<p>{{ p.body }}</p>
</div>
</div>
<script>
angular.module('httpApp', []).controller('HttpCtrl', function($scope, $http) {
$scope.posts = [];
$scope.caricamento = false;
$scope.errore = null;
$scope.carica = function() {
$scope.caricamento = true;
$scope.errore = null;
$http.get('https://jsonplaceholder.typicode.com/posts')
.then(function(risposta) {
$scope.posts = risposta.data;
})
.catch(function(err) {
$scope.errore = 'Impossibile caricare i dati.';
})
.finally(function() {
$scope.caricamento = false;
});
};
});
</script>
</body>
</html>
DOM
AngularJS gestisce il DOM tramite direttive. Le principali per il controllo della visualizzazione sono ng-show, ng-hide, ng-class, ng-style e ng-disabled.
HTML β ng-class e ng-style dinamici Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="domApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; }
.box { padding: 20px; border-radius: 8px; margin: 10px 0; transition: all 0.3s; text-align: center; font-size: 1.2rem; font-weight: bold; }
.verde { background: #dcfce7; color: #166534; }
.rosso { background: #fee2e2; color: #991b1b; }
.blu { background: #dbeafe; color: #1e40af; }
input[type=range] { width: 100%; }
button { padding: 8px 14px; margin: 4px; border: none; border-radius: 4px; cursor: pointer; }
</style>
</head>
<body>
<div ng-controller="DomCtrl">
<!-- ng-class con oggetto -->
<div class="box" ng-class="{verde: stato=='ok', rosso: stato=='errore', blu: stato=='info'}">
Stato: {{ stato }}
</div>
<button ng-click="stato='ok'">β
OK</button>
<button ng-click="stato='errore'">β Errore</button>
<button ng-click="stato='info'">βΉοΈ Info</button>
<hr>
<!-- ng-style dinamico -->
<p>Dimensione testo: {{ dimensione }}px</p>
<input type="range" ng-model="dimensione" min="12" max="48">
<p ng-style="{'font-size': dimensione + 'px', 'color': colore}">
Testo dinamico con AngularJS!
</p>
<button ng-click="colore='#4f46e5'">Viola</button>
<button ng-click="colore='#dc2626'">Rosso</button>
<button ng-click="colore='#16a34a'">Verde</button>
</div>
<script>
angular.module('domApp', []).controller('DomCtrl', function($scope) {
$scope.stato = 'info';
$scope.dimensione = 20;
$scope.colore = '#4f46e5';
});
</script>
</body>
</html>
Eventi
AngularJS offre direttive per gestire tutti gli eventi del mouse e della tastiera senza usare addEventListener direttamente.
Direttiva Evento corrispondente
ng-clickclick del mouse
ng-dblclickdoppio click
ng-mouseenter / ng-mouseleavehover del mouse
ng-keydown / ng-keyuptasto premuto/rilasciato
ng-changevalore di input cambiato
ng-submitinvio del form
ng-focus / ng-blurfocus/perdita focus su input
HTML β eventi mouse e tastiera Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="eventiApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; }
.zona { width: 200px; height: 100px; display: flex; align-items: center; justify-content: center;
border-radius: 8px; font-weight: bold; cursor: pointer; transition: all .2s; }
.normale { background: #e0e7ff; color: #3730a3; }
.hover { background: #4f46e5; color: #fff; }
input { padding: 8px; width: 100%; border: 1px solid #ccc; border-radius: 4px; margin: 8px 0; }
.log { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px; height: 80px; overflow-y: auto; font-size: .85rem; }
</style>
</head>
<body>
<div ng-controller="EventiCtrl">
<div class="zona"
ng-class="dentro ? 'hover' : 'normale'"
ng-mouseenter="dentro=true; aggiungiLog('Entrato!')"
ng-mouseleave="dentro=false; aggiungiLog('Uscito!')"
ng-click="aggiungiLog('Click! Contatore: ' + ++clic)">
{{ dentro ? 'π±οΈ Dentro!' : 'Passa il mouse' }}
</div>
<input type="text" ng-model="testo"
ng-keyup="aggiungiLog('Tasto: ' + $event.key)"
placeholder="Digita qualcosa...">
<p>Caratteri: {{ testo.length }}</p>
<div class="log">
<div ng-repeat="riga in log track by $index">{{ riga }}</div>
</div>
</div>
<script>
angular.module('eventiApp', []).controller('EventiCtrl', function($scope) {
$scope.log = [];
$scope.clic = 0;
$scope.testo = '';
$scope.aggiungiLog = function(msg) {
$scope.log.unshift(msg);
if ($scope.log.length > 10) $scope.log.pop();
};
});
</script>
</body>
</html>
Form
AngularJS gestisce i form automaticamente: ogni form ottiene un oggetto di stato con proprietΓ che indicano se Γ¨ stato modificato ($dirty), valido ($valid), toccato ($touched) e altri.
HTML β form con stato AngularJS Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="formApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; max-width: 500px; }
input, textarea { width: 100%; padding: 8px; margin: 4px 0 12px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }
input.ng-invalid.ng-dirty { border-color: #ef4444; background: #fef2f2; }
input.ng-valid.ng-dirty { border-color: #22c55e; background: #f0fdf4; }
button { padding: 10px 24px; background: #4f46e5; color: #fff; border: none; border-radius: 4px; cursor: pointer; }
button:disabled { background: #94a3b8; cursor: not-allowed; }
.stato { font-size: .85rem; color: #64748b; margin-top: 8px; }
</style>
</head>
<body>
<div ng-controller="FormCtrl">
<h2>Registrazione</h2>
<form name="regForm" ng-submit="invia(regForm)">
<label>Nome *</label>
<input type="text" name="nome" ng-model="utente.nome"
required minlength="3" placeholder="Minimo 3 caratteri">
<label>Email *</label>
<input type="email" name="email" ng-model="utente.email"
required placeholder="nome@esempio.it">
<label>EtΓ </label>
<input type="number" name="eta" ng-model="utente.eta"
min="18" max="99" placeholder="18-99">
<button type="submit" ng-disabled="regForm.$invalid">
Registrati
</button>
<p class="stato">
Form valido: {{ regForm.$valid ? 'β
' : 'β' }} |
Modificato: {{ regForm.$dirty ? 'Sì' : 'No' }}
</p>
</form>
<div ng-if="inviato" style="background:#dcfce7;padding:12px;border-radius:8px;margin-top:12px">
β
Benvenuto, <strong>{{ utente.nome }}</strong>! ({{ utente.email }})
</div>
</div>
<script>
angular.module('formApp', []).controller('FormCtrl', function($scope) {
$scope.utente = {};
$scope.inviato = false;
$scope.invia = function(form) {
if (form.$valid) { $scope.inviato = true; }
};
});
</script>
</body>
</html>
Validazione
AngularJS valida automaticamente i campi HTML5 (required, min, max, minlength, maxlength, pattern) e aggiunge classi CSS per mostrare lo stato.
ProprietΓ Significato
$valid / $invalidCampo/form valido o no
$dirty / $pristineCampo modificato o intatto
$touched / $untouchedCampo toccato (focus poi blur) o no
$errorOggetto con i tipi di errore attivi
HTML β messaggi di errore personalizzati Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="valApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; max-width: 460px; }
input { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;
margin: 4px 0; box-sizing: border-box; }
input.ng-invalid.ng-touched { border-color: #ef4444; }
input.ng-valid.ng-touched { border-color: #22c55e; }
.errore { color: #ef4444; font-size: .85rem; margin: 0 0 10px; }
</style>
</head>
<body>
<div ng-controller="ValCtrl">
<form name="f">
<label>Username</label>
<input type="text" name="user" ng-model="user"
required minlength="4" maxlength="12"
pattern="[a-zA-Z0-9]+">
<p class="errore" ng-if="f.user.$touched && f.user.$error.required">
β οΈ Username obbligatorio.
</p>
<p class="errore" ng-if="f.user.$touched && f.user.$error.minlength">
β οΈ Minimo 4 caratteri.
</p>
<p class="errore" ng-if="f.user.$touched && f.user.$error.pattern">
β οΈ Solo lettere e numeri.
</p>
<label>Password</label>
<input type="password" name="pwd" ng-model="pwd"
required minlength="8">
<p class="errore" ng-if="f.pwd.$touched && f.pwd.$error.required">
β οΈ Password obbligatoria.
</p>
<p class="errore" ng-if="f.pwd.$touched && f.pwd.$error.minlength">
β οΈ Minimo 8 caratteri.
</p>
<button ng-disabled="f.$invalid" style="padding:10px 20px;background:#4f46e5;color:#fff;border:none;border-radius:4px;cursor:pointer">
Registrati
</button>
</form>
</div>
<script>angular.module('valApp',[]).controller('ValCtrl',function($scope){});</script>
</body>
</html>
Animazioni
Il modulo ngAnimate aggiunge animazioni CSS automaticamente quando le direttive AngularJS mostrano o nascondono elementi. Basta includere il modulo e definire le classi CSS.
HTML β animazioni con ngAnimate Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="animApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular-animate.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; }
.box { padding: 20px; background: #4f46e5; color: #fff; border-radius: 8px;
margin: 12px 0; font-size: 1.1rem; font-weight: bold; text-align: center; }
/* Animazione ng-show/ng-hide */
.box.ng-hide-add { animation: fadeOut 0.4s; }
.box.ng-hide-remove { animation: fadeIn 0.4s; }
/* Animazione ng-repeat */
.item.ng-enter { animation: slideIn 0.4s; }
.item.ng-leave { animation: slideOut 0.3s; }
@keyframes fadeIn { from { opacity:0; transform:scale(.9); } to { opacity:1; transform:scale(1); } }
@keyframes fadeOut { from { opacity:1; } to { opacity:0; } }
@keyframes slideIn { from { opacity:0; transform:translateX(-20px); } to { opacity:1; transform:none; } }
@keyframes slideOut { from { opacity:1; } to { opacity:0; transform:translateX(20px); } }
button { padding: 8px 16px; margin: 4px; border: none; border-radius: 4px; cursor: pointer;
background: #4f46e5; color: #fff; }
.item { padding: 8px 12px; border: 1px solid #e2e8f0; border-radius: 6px; margin: 4px 0; }
</style>
</head>
<body>
<div ng-controller="AnimCtrl">
<button ng-click="visibile = !visibile">Toggle banner</button>
<div class="box" ng-show="visibile">π Animazione con ngAnimate!</div>
<hr>
<button ng-click="aggiungi()">+ Aggiungi</button>
<button ng-click="rimuovi()">- Rimuovi</button>
<div class="item" ng-repeat="i in items">Elemento {{ i }}</div>
</div>
<script>
angular.module('animApp', ['ngAnimate']).controller('AnimCtrl', function($scope) {
$scope.visibile = true;
$scope.items = [1, 2, 3];
var cnt = 4;
$scope.aggiungi = function() { $scope.items.push(cnt++); };
$scope.rimuovi = function() { if ($scope.items.length) $scope.items.pop(); };
});
</script>
</body>
</html>
Routing
Il modulo ngRoute permette di creare applicazioni Single Page (SPA) con navigazione tramite URL #/percorso senza ricaricare la pagina.
HTML β SPA con ngRoute Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="routeApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular-route.min.js"></script>
<style>
body { font-family: Arial; padding: 0; margin: 0; }
nav { background: #1e293b; padding: 12px 20px; }
nav a { color: #94a3b8; text-decoration: none; margin-right: 16px; font-weight: bold; }
nav a:hover { color: #fff; }
.pagina { padding: 30px; }
h2 { color: #4f46e5; }
</style>
</head>
<body>
<nav>
<a href="#/">π Home</a>
<a href="#/chi-sono">π€ Chi sono</a>
<a href="#/contatti">βοΈ Contatti</a>
</nav>
<!-- Qui ngRoute inietta la vista corrente -->
<div ng-view></div>
<script>
var app = angular.module('routeApp', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
template: '<div class="pagina"><h2>π Home</h2><p>Benvenuto nella nostra SPA con AngularJS!</p></div>'
})
.when('/chi-sono', {
template: '<div class="pagina"><h2>π€ Chi sono</h2><p>Sono un developer appassionato di AngularJS.</p></div>'
})
.when('/contatti', {
template: '<div class="pagina"><h2>βοΈ Contatti</h2><p>Email: info@esempio.it</p></div>'
})
.otherwise({ redirectTo: '/' });
});
</script>
</body>
</html>
Include
La direttiva ng-include carica frammenti HTML esterni (file separati) e li inserisce nella pagina. Γ utile per componenti riutilizzabili come navbar e footer.
HTML β ng-include e template inline Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="includeApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial; padding: 20px; }
.card { border: 1px solid #e2e8f0; padding: 16px; border-radius: 8px; margin: 8px 0; }
button { padding: 8px 16px; margin: 4px; border: none; border-radius: 4px;
cursor: pointer; background: #4f46e5; color: #fff; }
</style>
</head>
<body>
<div ng-controller="IncludeCtrl">
<h2>Scegli un template</h2>
<button ng-click="template='tmpl1.html'">Profilo Utente</button>
<button ng-click="template='tmpl2.html'">Statistiche</button>
<!-- ng-include carica il template selezionato -->
<div ng-include="template"></div>
<!-- Template definiti inline con script type="text/ng-template" -->
<script type="text/ng-template" id="tmpl1.html">
<div class="card">
<h3>π€ Profilo: {{ utente.nome }}</h3>
<p>Email: {{ utente.email }}</p>
<p>Ruolo: {{ utente.ruolo }}</p>
</div>
</script>
<script type="text/ng-template" id="tmpl2.html">
<div class="card">
<h3>π Statistiche</h3>
<p>Corsi completati: 12</p>
<p>Ore studiate: 48</p>
<p>Badge ottenuti: 5</p>
</div>
</script>
</div>
<script>
angular.module('includeApp', []).controller('IncludeCtrl', function($scope) {
$scope.template = 'tmpl1.html';
$scope.utente = { nome: 'Marco Rossi', email: 'marco@esempio.it', ruolo: 'Studente' };
});
</script>
</body>
</html>
Applicazione Completa
Mettiamo insieme tutto: un'app di gestione contatti con controller, filtri, form con validazione e operazioni CRUD.
HTML β app CRUD rubrica contatti Provalo tu βΆ
<!DOCTYPE html>
<html ng-app="rubricaApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
* { box-sizing: border-box; }
body { font-family: Arial; padding: 20px; background: #f8fafc; }
h1 { color: #1e293b; }
.form-box { background: #fff; padding: 20px; border-radius: 8px; margin-bottom: 20px;
border: 1px solid #e2e8f0; }
input { width: 100%; padding: 8px; margin: 4px 0 12px; border: 1px solid #cbd5e1;
border-radius: 4px; }
input.ng-invalid.ng-dirty { border-color: #ef4444; }
.btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; margin: 2px; }
.add { background: #4f46e5; color: #fff; }
.del { background: #ef4444; color: #fff; font-size: .8rem; }
.search { width: 100%; padding: 10px; border: 2px solid #4f46e5; border-radius: 6px;
font-size: 1rem; margin-bottom: 16px; }
table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 8px; overflow:hidden; }
th { background: #1e293b; color: #fff; padding: 10px; text-align: left; cursor: pointer; }
td { padding: 10px; border-bottom: 1px solid #f1f5f9; }
tr:hover td { background: #f0f4ff; }
.vuoto { text-align: center; color: #94a3b8; padding: 20px; }
.errore { color: #ef4444; font-size: .83rem; margin: -8px 0 8px; }
</style>
</head>
<body>
<div ng-controller="RubricaCtrl">
<h1>π Rubrica Contatti</h1>
<!-- Form aggiunta -->
<div class="form-box">
<form name="f" ng-submit="aggiungi(f)" novalidate>
<input type="text" ng-model="nuovo.nome" placeholder="Nome *"
required minlength="2">
<p class="errore" ng-if="f.nome && f.nome.$touched && f.nome.$error.required">Nome obbligatorio</p>
<input type="email" ng-model="nuovo.email" placeholder="Email *"
name="email" required>
<p class="errore" ng-if="f.email.$touched && f.email.$invalid">Email non valida</p>
<input type="tel" ng-model="nuovo.tel" placeholder="Telefono">
<button class="btn add" type="submit" ng-disabled="f.$invalid">
β Aggiungi contatto
</button>
</form>
</div>
<!-- Ricerca -->
<input class="search" type="text" ng-model="cerca" placeholder="π Cerca contatto...">
<table>
<tr>
<th ng-click="ordine='nome'">Nome β</th>
<th ng-click="ordine='email'">Email β</th>
<th>Telefono</th>
<th>Azioni</th>
</tr>
<tr ng-repeat="c in contatti | filter:cerca | orderBy:ordine">
<td>{{ c.nome }}</td>
<td>{{ c.email }}</td>
<td>{{ c.tel || 'β' }}</td>
<td><button class="btn del" ng-click="elimina($index)">π Elimina</button></td>
</tr>
<tr ng-if="(contatti | filter:cerca).length === 0">
<td colspan="4" class="vuoto">Nessun contatto trovato.</td>
</tr>
</table>
<p style="margin-top:12px;color:#64748b">Totale: {{ contatti.length }} contatti</p>
</div>
<script>
angular.module('rubricaApp', []).controller('RubricaCtrl', function($scope) {
$scope.ordine = 'nome';
$scope.nuovo = {};
$scope.contatti = [
{ nome: 'Alice Bianchi', email: 'alice@esempio.it', tel: '333-111-2222' },
{ nome: 'Marco Rossi', email: 'marco@esempio.it', tel: '347-555-6666' },
{ nome: 'Sofia Ferrari', email: 'sofia@esempio.it', tel: '' }
];
$scope.aggiungi = function(form) {
if (form.$valid) {
$scope.contatti.push(angular.copy($scope.nuovo));
$scope.nuovo = {};
form.$setPristine();
}
};
$scope.elimina = function(i) {
$scope.contatti.splice(i, 1);
};
});
</script>
</body>
</html>
Esercizi pratici
π Esercizio 1 β Lista della spesa
Crea un'app AngularJS con: campo input per aggiungere prodotti, lista con ng-repeat, pulsante per eliminare ogni prodotto, contatore degli articoli, filtro di ricerca in tempo reale e totale calcolato (ipotizzando un prezzo fisso per ogni prodotto).
π Esercizio 2 β Quiz interattivo
Costruisci un quiz con AngularJS: array di 5 domande con risposta corretta, mostrare una domanda alla volta con ng-show, bottoni per le risposte con ng-click, punteggio aggiornato in tempo reale, schermata finale con risultato e pulsante per ricominciare.
π Esercizio 3 β Dashboard meteo
Crea una dashboard con $http: al caricamento fai un GET a https://wttr.in/?format=j1 o un'API pubblica a tua scelta, mostra temperatura, condizione meteo e icona. Aggiungi un filtro per scegliere l'unitΓ (Β°C / Β°F) usando un filtro personalizzato AngularJS.
E ora?
Complimenti! Hai completato il corso su AngularJS. Ora conosci le direttive principali, il data binding bidirezionale, i controller, lo scope, i filtri, i servizi, $http, le form con validazione, le animazioni e il routing.
Cosa hai imparato:
Direttive fondamentali: ng-app, ng-model, ng-repeat, ng-if, ng-click...
Data binding bidirezionale tra Model e View
Controller e $scope per la logica dell'applicazione
Filtri per formattare e cercare dati
Servizi $http per chiamate AJAX
Validazione form avanzata con messaggi personalizzati
ngAnimate per transizioni CSS automatiche
ngRoute per applicazioni Single Page (SPA)
Il passo successivo? Migra verso Angular moderno (v2+) che usa TypeScript, componenti e un'architettura piΓΉ scalabile, oppure esplora altri framework come Vue e React.