SPA nelle applicazioni AEM

Il framework delle applicazioni a pagina singola nelle app AEM consente di ottenere prestazioni elevate da un’app AngularJS, consentendo agli autori (o ad altro personale non tecnico) di creare e gestire i contenuti dell’app tramite l’ambiente di editor drag-and-drop ottimizzato per il tocco, tradizionalmente riservato alla gestione dei siti web. Hai già un sito costruito con l'AEM? Con le app AEM puoi riutilizzare facilmente contenuti, componenti, flussi di lavoro, risorse e autorizzazioni.

Modulo applicativo AngularJS

Le app AEM gestiscono gran parte della configurazione AngularJS, inclusa la creazione del modulo di livello superiore dell’app. Per impostazione predefinita, questo modulo è denominato "AEMAngularApp" e lo script responsabile della sua generazione è reperibile (e sovrapposto) in /libs/mobileapps/components/angular/ng-page/angular-app-module.js.jsp.

Parte dell’inizializzazione dell’app consiste nello specificare da quali moduli AngularJS dipende l’app. L’elenco dei moduli utilizzati dall’app è specificato da uno script che si trova in /libs/mobileapps/components/angular/ng-page/angular-module-list.js.jsp e può essere sovrapposto dal componente pagina delle tue app per richiamare eventuali moduli AngularJS aggiuntivi richiesti dall’app. Ad esempio, confronta lo script precedente con l’implementazione Geometrixx (che si trova in /apps/geometrixx-outdoors-app/components/angular/ng-geometrixx-page/angular-module-list.js.jsp).

Per supportare la navigazione tra gli stati distinti nell’app, lo script del modulo angular-app scorre tutte le pagine discendenti della pagina dell’app principale per generare un set di "route" e configura ogni percorso nel servizio $routeProvider di Angular. Ad esempio, osserva lo script del modulo angular-app generato dall'app di Geometrixx Outdoors: (il collegamento richiede un'istanza locale) http://localhost:4502/content/phonegap/conference-app/en/home.angular-app-module.js

Accedendo all’app AEMAngularApp generata, trovi una serie di route specificate come segue:

$routeProvider
.when('/content/phonegap/geometrixx-outdoors/en/home/products/:id', {
    templateUrl: 'home/products.template.html',
    controller: 'contentphonegapgeometrixxoutdoorsenhomeproducts'
})

L'esempio precedente illustra in particolare un esempio di passaggio di un parametro come parte del percorso. In questo esempio, indica che quando viene richiesto un percorso che soddisfa il modello specificato (https://experienceleague.adobe.com/content/phonegap/geometrixx-outdoors/en/home/products/:id?lang=it), deve essere gestito dal modello home/products.template.html e utilizzare il controller "contentphonegapgeometrixxoutdoorsenhomeproducts".

Il modello da caricare quando viene richiesta questa route è specificato dalla proprietà templateUrl. Questo modello contiene i HTML dei componenti AEM inclusi nella pagina e tutte le direttive AngularJS necessarie per collegare il lato client dell’applicazione. Per un esempio di direttiva AngularJS in un componente Geometrixx, consulta la riga 45 del file template.jsp del pannello di scorrimento (https://experienceleague.adobe.com/apps/geometrixx-outdoors-app/components/swipe-carousel/template.jsp?lang=it).

Controller di pagina

Nelle stesse parole di Angular, "un controller è una funzione di costruzione di JavaScript utilizzata per potenziare l'ambito dell'Angular". (source) Ogni pagina in un'app AEM viene collegata automaticamente a un controller che può essere potenziato da qualsiasi controller che specifica un frameworkType di angular. Osserva il componente ng-text come esempio (https://experienceleague.adobe.com/libs/mobileapps/components/angular/ng-text?lang=it), incluso il nodo cq:template che si assicura che ogni volta che questo componente viene aggiunto a una pagina, includa questa importante proprietà.

Per un esempio più complesso di controller, apri lo script ng-template-page controller.jsp (in /apps/geometrixx-outdoors-app/components/angular/ng-template-page). Di particolare interesse è il codice JavaScript generato al momento dell’esecuzione, che esegue il rendering come segue:

// Controller for page 'products'
.controller('contentphonegapgeometrixxoutdoorsenhomeproducts', ['$scope', '$http', '$routeParams',
    function($scope, $http, $routeParams) {
        var sku = $routeParams.id;
        var productPath = '/' + sku.substring(0, 2) + '/' + sku.substring(0, 4) + '/' + sku;
        var data = $http.get('home/products' + productPath + '.angular.json' + cacheKiller);

        /* ng-product component controller (path: content-par/ng-product) */
        data.then(function(response) {
            $scope.contentparngproduct = response.data["content-par/ng-product"].items;
        });

        /* ng-image component controller (path: content-par/ng-product/ng-image) */
        data.then(function(response) {
            $scope.contentparngproductngimage = response.data["content-par/ng-product/ng-image"].items;
        });
    }
])

Nell'esempio precedente, il parametro del servizio $routeParams viene preso e quindi massaggiato nella struttura di directory in cui sono memorizzati i dati JSON. Gestendo lo SKU id in questo modo, è possibile fornire un unico modello di prodotto in grado di eseguire il rendering dei dati del prodotto per migliaia di prodotti potenzialmente distinti. Si tratta di un modello molto più scalabile che richiede un percorso individuale per ogni elemento in un database di prodotti (potenzialmente) di grandi dimensioni.

Ci sono anche due componenti in azione qui: ng-product potenzia l'ambito con i dati estratti dalla chiamata $http precedente. In questa pagina è inoltre presente un'immagine ng che a sua volta potenzia l'ambito con il valore che recupera dalla risposta. In virtù del servizio $http di Angular, ogni componente attende pazientemente il completamento della richiesta e il completamento della promessa creata.