Angularin käyttö portletin JSP-sivuilla

Angular-frameworkia käytetään portleteissa neljässä yhteydessä:
(1) JSP-tiedostoissa (tiedosto vastaa yhtä websivua), jossa se määrittelee Angularin MVC-mallin sidonnan HTML-elementteihin.
(2) Javascript-tiedostoissa, joissa Angularin moduleiden ja kontrollereiden määritys on.
(3) Bootstrap-toiminto, joka on viimeiseksi ladattavassa Javascript-tiedostossa.
(4) Javascript-tiedosto, jossa on toteutettu sivunvaihdot (router).

(1) JSP-sivu ja Angular:

JSP-sivu ei ole ongelma HTML-tagituksen ja siihen liittyvän Angularin suhteen, koska HTML- ja Javascript-osuuksia ei JSP-sivua ladattaessa prosessoida. Avaavalla JSP-sivulla merkitään ainoastaan mihin kohtaan uusi sivu aina vaihdetaan, mikä on siten SPA-portletin pääkehys. Tämä on ainut avaavan JSP-sivun HTML-tagitus tässä seppien esimerkissä. Toki voi avaavalle sivulle muutakin kiinteää HTML-sisältöä lisätä. Nämä lisäykset luonnollisesti näkyvät kaikkien avattavien sivujen ympärillä, koska avattava uusi sivu on vain div-elementin uusi sisältö. Kehys merkitään esimerkiksi näin, eli se sisältää ng-controller direktiivissa Angularin kontrollerin määrityksen sekä sivunvaihdon mahdollistavan ng-view direktiivin:

Div-elementin attribuutit: id=”div0″ ng-controller=”dataGridCon” ng-view

Muut JSP-sivut taas muodostavat SPA-portletin varsinaisen sisällön, ja ne avataan edellä määriteltyyn div-elementtiin. Niiden alkuun tarvitaan apua JSP-tagitukselta (ajetaan serverin puolella) portletin namespacen hakemiseen JSP-sivua ladataessa (ks. aikaisemmat blogit, mihin se kirjoitetaan talteen). JSP-sivun alkuun siis tarvitaan merkinnät (POUtil on yksinkertainen Java-luokka lukemiseen):

<%@ page import=”fi.fabercon.portlet.util.PoUtil” %>
<% String ns = PoUtil.getNamespace(); %>

Tämä namespace tieto Javassa (ns) on sama, kuin mikä luetaan avaavassa JSP-sivussa selaimessa Javascriptin globaaliin muuttujaan (ns.namespace). Tämän jälkeen Angularin lisääminen JSP-sivulla on yksinkertaista, käytät vain edellä haettua ns-muuttujaa identifioimaan elementteja. Muuten merkinnät ovat täysin Angularin yleisten esimerkkien mukaisia. Mitään Angularin ng-controller määritystä ei muille kuin avaavalle JSP-sivulle siis tule. Nämä määritykset hoidetaan Angularin $route-servicen määrityksessä. Esimerkiksi button-input-elementin sidonnasta Angulariin (ng-click on Angular-direktiivi):

<input type=”button” id=”<%=ns%>btnSelect” value=”Select by Id” ng-click=”btnSelectItem_click();” />

Tai text-input-elementin kaksisuuntainen sidonta Angularin Modelilta tuomaan dataan:

<input type=”text” id=”<%=ns%>txtName” ng-model=”company.name” value=”{{company.name}}” />

Alisivuilla ei tarvita mitään muuta. Angular-controllerin määritykset ovat SPA-portletissa avaavalla JSP-sivulla.

(2) Javascriptiin sijoitettu Angular-koodi:

AngularJS-koodi sijoitetaan Angular-kontrollereihin. Selkeänä perustana kannattaa pitää yksi moduli ja sen ainut kontrolleri per tiedosto. Yksi Angular-javascript-tiedosto kapseloi siis yhden kontrollerin, eli yhden JSP-sivun Javascript-koodin. Angular-modulit määritettiin avaavalla JSP-sivuilla ja globaalit muuttujat kapseloitiin getNamespace-metodissa.

Angular-modulin ja -controllerin määritys ei poikkea tavanomaisesta Angularin käytöstä web-sivuilla. Tiedoston perusrakenteesta esimerkki:

var ns = gsPortletinNimiNS; // siirto helppoon lokaaliin muuttujanimeen
console.log(”javascript-tiedoston-nimi: ” + ns);

ns.controlMod.controller(ns.namespace + ”dataItemCon”, [ ”$scope”, ”$routeParams”, ”angService”,
function($scope, $routeParams, angService)
{
  // modulin toteutus: muuttujat, funktiot, $scope-muuttujat, @scope-funktiot ym.
}

Angularin modulin määritys löytyy Angularin massiivisesta dokumentaatiosta. Kontrollerin sisältö on tavanomainen (ikäänkuin Javan luokkamääritys), siellä voidaan määritellä:
– normaaleja Javascript-funktioita
– $scope-funktioita (esim. $scope.btnSelectItem_click = function (…) {….} ) ovat funktioita, joita käytetään Angular-modulin rajaamalta alueelta, esimerkiksi HTML-elementtien tapahtumankäsittelyfunktioina.
– normaaleja Javascript-muuttujia, joissa voidaan tallettaa tietoja (ts. sovelluksen tilaa)
– $scope-muuttujat (esim. $scope.company) ovat lisäksi tarkoitettuja sitomaan data HTML-elementteihin
– $scope-muuttujat ja -funktiot muodostavat modulin julkisen rajapinnan, muu ei näy modulin ulkopuolelle

(3) Bootstrap-toiminto:

AngularJS lataa (sisäinen bootstrap) modulit ja servicet automaattisesti, jos niiden latausta ei määritellä. On hyvin todennäköistä, että SPA-toiminto ei vaadi erillistä latausta, mutta monimutkaisissa tilanteissa ei ole varmuutta miten automaattinen lataus toimii. Tämän takia on varmempaa määritellä lataus ei bootstrappaus itse viimeiseen ladattavaan Javascript-tiedostoon, kun kaikki määrittelyt ovat valmiina.

Portleteissa Eclipse IDEn wizard laatii aina mukaan main.js-tiedoston. Tämä sopii bootstrapin paikaksi. Liferay-portlet.xml -tiedostossa kyseisen tiedoston lataus pitää olla viimeisenä. Esimerkki main.js:n sisällöstä:

var ns = gsPortletinNimiNS;
var divElem = document.(ns.namespace + ”div0”);
angular.bootstrap(divElem, [ ns.namespace + ”appMod” ]);

DivElem-muuttuja viittaa avaavan JSP-sivun SPA-kehyksen div-elementtiin.

(4) Angularin route-toiminto:

Seuraavassa blogissa käsitellään Angularin $route-toimintoa SPA-portletissa.