Nonostante AngularJS sia un framework molto potente ci sono svariati motivi per volerlo integrare con codebase pre-esistente.
Anzitutto AngularJS si occupa principalmente dell'architettura dell'applicazione, senza toccare gli aspetti di user interface quali possono essere caroselli di immagini, finestre modali e controlli di form avanzati.
In secondo luogo spesso ci troviamo a dover applicare AngularJS su stack già definiti. Il caso più semplice è dover integrare la logica client-side su un tema di Bootstrap. Un'altro è quello in cui si debba utilizzare un plugin jQuery dovendosi interfacciare con il model di un controller AngularJS.
Il grosso vantaggio in tutti questi scenari è che AngularJS è particolarmente adatto per l'integrazione in ambienti jQuery-like (inclusi quindi jQuery2 e Zepto) visto che parte delle sue API come angular.element
utilizzano l'engine di jQuery quando disponibile.
Uno degli esempi migliori di questa integrazione è AngularUI che unisce AngularJS con Bootstrap 3.
In questo articolo vedremo come utilizzare due semplici plugin jQuery all'interno di un'applicazione AngularJS.
Una questione di direttive
Nell'architettura di un'applicazione AngularJS l'unico modo per interagire con il DOM è attraverso l'uso di una direttiva. È qui che dovremo indirizzarci per integrare i nostri plugin.
Nella sua forma più semplice una direttiva può essere dichiarata con la seguente sintassi:
angular.module('myApp', [])
.directive('myDirective', function () {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
element.addClass('is-active');
}
};
});
// utilizzare come: <div my-directive></div>
L'oggetto di definizione della direttiva ha due proprietà:
Proprietà | Descrizione |
---|---|
restrict | come possiamo utilizzare la direttiva nella view. Nel nostro caso come attributo (A ) oppure come classe (C ). |
link | la funzione che va lanciata su ogni elemento DOM a cui è associata la direttiva. |
Nell'esempio precedente la direttiva my-directive
aggiunge una classe ad ogni elemento su cui è applicata mutuando il metodo .addClass
di jQuery (Scarica l'esempio1 | guarda live).
Creare una direttiva per i tooltip
Nell'esempio seguente vedremo come utilizzare quanto visto finora per creare una direttiva per qTip2, un plugin jQuery per la realizzazione di tooltip custom.
Il nostro html di esempio sarà:
<span my-tooltip title="Testo nel tooltip">Testo nel box</span>
Per un'integrazione basilare la direttiva da definire è molto semplice:
angular.module('myApp', [])
.directive('myTooltip', function () {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
element.qtip();
}
};
});
Scarica l'esempio 2 e guarda la direttiva in azione (live).
Che il plugin funzioni correttamente e che si integri alla perfezione con AngularJS è dimostrato dal fatto che anche utlizzando un'espressione per valorizzare l'attributo title
del tag, questa viene correttamente passata al plugin.
Scarica l'esempio 3 e guarda la direttiva in azione (live).
Passare variabili di configurazione
Sebbene questa direttiva possa andare bene per un utilizzo generico, qTip2 supporta una serie di parametri di configurazione per personalizzarne gli stili ed il posizionamento.
Nella nostra direttiva passeremo questi parametri come valore dell'attributo my-tooltip
:
<span my-tooltip="{position: { my: 'left center'}}" title="Testo nel tooltip">Testo nel box</span>
angular.module('myApp', [])
.directive('myTooltip', function () {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
var config = scope.$eval(attrs.myTooltip);
element.qtip(config);
}
};
});
Scarica l'esempio 4 e guarda la direttiva in azione (live).
Carosello di immagini
Il secondo caso che vedremo è la realizzazione di un carosello di immagini con cycle2.
Per garantire flessibilità e semplicità d'uso, dovremo sviluppare una direttiva più avanzata rispetto a quella del tooltip.
Come primo passo stamperemo un array di immagini images
utilizzando le direttive ng-repeat
e ng-src
:
<div id="slideshow">
<img class="slide" ng-src="{{image}}" ng-repeat="image in images" />
</div>
Quindi, come per l'esempio precedente lanceremo il plugin nella funzione link
della direttiva:
angular.module('myApp', [])
.directive('mySlideshow', function () {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
var config = angular.extend({
slides: '.slide'
}, scope.$eval(attrs.mySlideshow));
setTimeout(function () {
element.cycle(config);
}, 0);
}
};
});
Di default utilizzeremo la classe slide
come identificativo di ogni elemento del carosello. Questo ci permetterà di utilizzare facilmente anche contenuti testuali o misti.
Da notare che la chiamata al plugin è inserita in un timeout a zero. Questo permette di posticipare l'esecuzione del plugin dopo la fase di rendering di AngularJS, evitando così che possa partire prima che ng-repeat
abbia finito il proprio ciclo.
Ecco una versione funzionante dello script (live).
Template predefinito
Una delle feature di Cycle 2 è il paginatore automatico. Per attivarlo basta inserire all'interno dello slider, il codice:
<div class="cycle-pager"></div>
Seguendo quanto fatto finora potremmo aggiungerlo nella view. Tuttavia nel nostro caso vogliamo inserirlo come feature di default per tutti gli slideshow e per farlo utilizzeremo due proprietà delle direttive di AngularJS:
Proprietà | Descrizione |
---|---|
template | permette di definire un template di default per i contenuti delle direttive. |
transclude | permette di ricopiare all'interno del template la parte di view contenuta originariamente nella direttiva, mantenendone inalterato lo scope. |
Il codice di my-slideshow
diventerà quindi:
angular.module('myApp', [])
.directive('mySlideshow', function () {
return {
restrict: 'AC',
transclude: true,
template: '<div ng-transclude></div><div class="cycle-pager"></div>',
link: function (scope, element, attrs) {
var config = angular.extend({
slides: '.slide'
}, scope.$eval(attrs.mySlideshow));
setTimeout(function () {
element.cycle(config);
}, 0);
}
};
});
L'uso della direttiva ng-transclude
nel template indica dove andranno inseriti i contenuti originali della view.
Ecco il risultato finale. (live).
Solo l'inizio
Queste due direttive di esempio sono solo il punto di inizio per comprendere le potenzialità dell'integrazione di plugin jQuery nel rispetto degli standard di AngularJS.
In base alle API di ogni plugin, si possono sfruttare caratteristiche come, ad esempio, il $watch su una proprietà per gestire dinamicamente il contenuto visualizzato, oppure alterare valori dello scope esterno utilizzando la gestione 2-way dell'attributo scope.
Per approfondire ulteriormente: