Struttura di una applicazione UI5

Prosegue da: Creazione di una webapp in OpenUI5

Come visto nel precedente post, la struttura base di una applicazione UI5 è abbastanza contorta. Proverò a fare un pò di chiarezza spiegandone a grandi linee le componenti principali, almeno per quello che sono riuscito a capire nei quindici giorni in cui ci ho giocato. Tutto il contenuto dell'applicazione è, per convenzione, nella cartella "webapp".

I file principali nella root dell'app sono:

  • manifest.json: contiene le configurazioni del progetto. In particolar modo qui vengono descritte le caratteristiche principali del progetto stesso (titolo, tipo, descrizione, dipendenze ecc..); i datasource, ovvero le sorgenti esterne di dati (servizi rest, file JSON, ecc..) e i modelli costruiti sopra di essi; la configurazione del sistema di routing, il meccanismo di navigazione interno all'app.
  • Component.js: il controller di base dell'applicazione. E' usato per ospitare funzioni comuni a tutta l'applicazione, oltre che per svolgere operazioni di inizializzazione.

Sono poi state create queste directory:

  • i18n: stringhe localizzate usate nell'UI.
  • model: contiene file Javascript per operare sui dati (ad esempio funzioni di formattazione, o di recupero dati per le modalità non gestite nativamente da UI5).
  • resources: risorse statiche (immagini eccetera).
  • css: autoesplicativo.
  • view: file XML che rappresentano elementi grafici (schermate o parti di esse). Tutti i files hanno estensione .view.xml.
  • controller: file Javascript che contengono le funzionalità usate dagli elementi grafici. Tipicamente c'è un controller per ciascuna view. Tutti i files hanno estensione .controller.js.

Le cartelle più interessanti per un primo approccio sono le ultime due elencate sopra: la struttura degli elementi grafici (di primo acchito le pagine) e le relative funzionalità implementate in Javascript. L'applicazione che abbiamo inizializzato nel precedente post ha un'unica pagina (per giunta spoglia). La vista è realizzata così:

 <mvc:View controllerName="it.tutorial.provaUI5.controller.MainView"
  displayBlock="true"
  xmlns="sap.m"
  xmlns:mvc="sap.ui.core.mvc">
  <App id="idAppControl" >
    <pages>
      <Page title="{i18n>title}">
        <content></content>
      </Page>
    </pages>
  </App>
</mvc:View>

Il blocco view contiene il riferimento al nome del controller e i namespace (le "librerie" di componenti XML utilizzabili in questo contesto). Il resto dell'applicazione è un oggetto di tipo app, che a sua volta contiene un blocco pages, che a sua volta contiene una Page con una proprietà (title), che a sua volta contiene un content (per ora vuoto).

Si noti come il titolo della pagina è rappresentato con questa dicitura:

{i18n>title}

Le parentesi graffe indicano il fatto che il contenuto sarà interpretato da UI5. La rappresentazione indica che la stringa da usare è la variabile title all'interno del modello dati i18n, che è collegato di default ai file di localizzazione citati prima.

La pagina è collegata a un controller, fatto così:

sap.ui.define([
  "it/tutorial/provaUI5/controller/BaseController"
], function(Controller) {
  "use strict";

  return Controller.extend("it.tutorial.provaUI5.controller.MainView", {
  
  // Qui possiamo mettere ne nostre funzioni custom
  
  });
});

Questa struttura indica ad UI5 di caricare le dipendenze esterne indicate nell'elenco (nel nostro caso it/tutorial/provaUI5/controller/BaseController), e una volta caricate costruire una estensione dell'oggetto BaseController e restituirla. Tutte le funzioni che vogliamo rendere disponibili alla view collegata a questo controller devono essere scritte dove indicato.

Tra parentesi, il BaseController non è un oggetto standard di libreria, bensì un modulo custom creato dal template e che a sua volta estende il vero oggetto base Controller. Nel BaseController sono messe le funzioni di utilità che vogliamo rendere disponibili a tutti i controller.

Proviamo a fare un piccolo esperimento: voglio mostrare del testo nella nostra pagina iniziale, e voglio fare in modo che questo testo sia letto da un modello dati custom inizializzato (in maniera banale) nel controller della pagina stessa.

A livello di controller, devo definire la funzione onInit() (funzione standard del ciclo di vita del controller, che viene chiamata all'inizializzazione) e dentro questa creare un JSONModel con dei dati statici. Il modello lo chiameremo myModel, e la stringa del titolo dara myTitle. Il file del controller sarà così (riferimenti API):

sap.ui.define([
  "it/tutorial/provaUI5/controller/BaseController",
  "sap/ui/model/json/JSONModel"
], function(Controller, JSONModel) {
  "use strict";

  return Controller.extend("it.tutorial.provaUI5.controller.MainView", {

	onInit: function(){
		let myModel = new JSONModel({
			myTitle: "Il mio fantastico titolo!"
		});
		this.getView().setModel(myModel, "myModel");
	}

  });
});

Come si vede abbiamo aggiunto alle dipendenze JSONModel e poi abbiamo popolato la funzione onInit con la creazione del modello dati e l'associazione dello stesso alla vista.

La vista è modificata come segue:

 <mvc:View controllerName="it.tutorial.provaUI5.controller.MainView"
  displayBlock="true"
  xmlns="sap.m"
  xmlns:mvc="sap.ui.core.mvc">
  <App id="idAppControl" >
    <pages>
      <Page title="{i18n>title}">
	<content>
		<Text text="{myModel>/myTitle}"/>
	</content>
      </Page>
    </pages>
  </App>
</mvc:View>

Abbiamo semplicemente aggiunto un oggetto di testo, e come testo gli abbiamo passato {myModel>/myTitle}.

Avviamo il server locale:

npm start

E, alla pagina localhost:8080, dovremmo avere qualcosa del genere:

Voilà!