Archivi tag: JSON

UaEjs: un template in Javascript

Mi ha sempre disturbato comporre la pagina seguendo il rendering dei dati sul server per poi inviarla al client. Mi rendo conto che è la tecnica più diffusa e che inoltre esistono centinaia di ottimi tool in tutti i linguaggi per eseguire la composizione della pagina.
Ma mi piace pensare che, quando il client effetta  una request per aggiornare i contenut,siano spediti  solo i dati e che ogni azione di impaginazione sia fatta dal client stesso, questa può apparire come una fissazione vista la tendenza prevalente. L’idea è nata dall’esigenza di realizzare un client completamente agnostico rispetto al server.Questo risultato si può ottenere solo limitando l’attività del server al solo invio di dati (in formato XML o JSON) e facendo carico al client di tutta l’attività di rendering. Avendo come riferimento all’architettura Model View Control si otterrebbe una situazione in cui le attività del modulo View e quelle del Control sarebbero effettuate nel client.
Questa scelta probabilmente farà inorridire tutti i cultori del PHP; questo non lo considero un grosso problema,purtroppo anche gli amanti di Django, Rails e tools simili saranno forse contrariati. Ebbene qust’ultimi sappiano che è possibile continuare ad usare i loro amati framework semplicemente rinunciando ad utilizzare la componente View.
L’accidente che mi ha convinto della mia scelta, oltre al fastidio di dipendere in maniera troppo vincolante dal tipo di server, è stato quello di realizzare un piccolo applicativo che funzionasse su di un DVD, un qualsiasi supporto USB, su qualsiasi computer e con qualsiasi sistema operativo.
Se il sito non prevede contenuti variabili si può realizzare con pagine HTML statiche;le cose vanno diversamente se i dati sono il risultato di un lavoro in itinere che deve andare avanti per anni e se gli operatori sono completamente digiuni di HTML e magari usano dei semplici fogli EXCEL per archiviare i dati. Peggio ancora se l’applicativo prevede delle query con JOIN fra tabelle, ad esempio nel caso di una biblioteca un report che colleghi autori e testi. E’ ovvio che in questo caso le pagine HTML statiche non vanno bene mentre si potrebbe immaginare di usare dei semplici file CSV peri dati, delegando al client anche eventuali attività per semplici query. A questo scopo esistono specifici tool per disporre di un sql semplificato dal lato client, in ogni caso non è complicato realizzare con Javascript semplici filtri e join. La parte più delicata resta quella del rendering dei dati .
Un’altra scelta è stata quella di utilizzare Javascript come linguaggio embedded e non un linguaggio di markup. In questo modo, oltre ad evitare la noia di imparare un nuovo linguaggio, si viene incontro alle abitudini dei numerosissimi utilizzatori di PHP, favorendo una loro eventuale conversione; soprattutto si possono utilizzare tutte le funzionalità di Javascript per i calcoli, la gestione delle stringhe e tutto il resto.
Vagando su internet alla ricerca di materiale per il mio progetto mi sono imbattuto in una pagina di John Resig (l’autore di jquery)
http://ejohn.org/blog/javascript-micro-templating/

Malgrado il suo commento minimalista:
“ I’ve had a little utility that I’ve been kicking around for some time now that I’ve found to be quite useful in my JavaScript application-building endeavors. It’s a super-simple templating function that is fast, caches quickly, and is easy to use. I have a couple tricks that I use to make it real fun to mess with.“
ho capito che era proprio quello che cercavo.
Accantonato rapidamente un acutissimo attacco d’invidia, mi sono messo a studiare il codice. Poi un poco perché volevo un strumento del quale padroneggiassi tutti i dettagli, un poco spinto da orgoglio senile ho deciso di usare la proposta di J.Resig solo come ispirazione per implementare un mio template.
Sono anni che lo uso, non mi ha mai tradito. La massima soddisfazione l’ho raggiunta quando sono riuscito a far funzionare lo stesso client – senza modificare una virgola – con Django, Rails, Tomcat, delle CGI e infine con dei files CSV.

Scaricando il codice si hanno ha disposizione diversi esempi ed un ambiente didattico per meglio comprenderne il funzionamento e l’architettura.

Il template si trova in uaejs.js
Espone due funzioni:
var html=UaEjs.build(ejs,data)

dove ejs è il modello e data sono in formato JSON
e
var rs=UaEjs.compile(ejs,data)
rs è un object  JSON  rs={html:<html source>,js:<javascript source>}
ed è comodo per il debug.

La notazione utilizzata è molto semplice:
Per immergere Javascript si utilizzano i tag <% %> per l’apertura e la chiusura.
Per assegnare una valore da visualizzare <%= %>.
Esempio:

HTML ospitante:

<div id='ua'></div>

Modello ejs:

 <h3><%=titolo%></h3>
 <ul>
 <% for(var i=0; i<materie.length; i++) {%>
 <li>
 <%=materie[i]%>
 </li>
 <%}%>
 </ul>
 <%=anno%>
 <br/>
 <%=loc%>

Dati:
{
“titolo”: “Discipline”,
“anno”: “2015”,
“loc”: “Italia”,
“materie”: [“lettere”, “lingue”, “filosofia”, “matematica”, “fisica”, “informatica”, “legge”, “chimica”]
}

Script nel file HTML ospitante:

<script type="text/javascript">
var ejs = UaRq.rqsGet("es.ejs", null, null, 'text').responseText;
var data = UaRq.getJson("es.json", {}, null, null);
var html = UaEjs.build(ejs, data);
document.getElementById('ua').innerHTML = html;
</script>

L’uso della libreria UaRq serve per gestire le chiamate AJAX. Può essere sostituita da un’altra equivalente. Bisogna fare attenzione alla lettura dei files JSON; se si leggono come semplici files di testo vanno convertirli in object JSON.
Nel codice allegato vi sono diversi esempi che permettono di visualizzare tutte le componenti in gioco:
dati nel formato JSON.
Template EJS
Javascript intermedio generato per eseguire il rendering
Sorgente HTML
HTML

E’ possibile fare delle prove con l’opzione edit disponibile per modificare sia JSON che EJS e poi provare con l’opzione compile.
L’ambiente di test è più complesso, ma sono disponibile degli script bash (es0.sh, es1.sh ..) che eseguono tutto il lavoro. Per effettuare i test è necessario node.js.
Per installarlo in Linux
apt-get install node.

 Gli esempi (uaejs.tar.gz) non sono molto commentati, ma sono contemplati diversi casi sia per quanto riguarda la soluzione adottata sia per la tipologia di dati.
Per provare gli esempi è disponibile un semplice server.py; è necessario solo con IE (restituisce errore 200 quando la response alle request AJAX è un file locale) per tutti gli altri è sufficiente caricare il file index.html.

JSONP ci libera dal dominio

L’introduzione di AJAX ha permesso un vero salto di qualità nella realizzazione di siti dinamici dando la possibilità di creare dei client implementati con javascript che dialogano con il server senza essere costretti per ogni request a ricaricare l’intera pagina. Vi sono delle situazioni (campi di lookup, help, liste, ..) per le quali l’uso di AJAX è di fatto indispensabile.
Nei browser per motivi di sicurezza ( Same Policy Origin) è impossibile effettuare chiamate verso domini diversi da utilizzato per caricare la pagina.
In linea di massima questa limitazione non costituisce un problema nella progettazione di un sito, ma vi sono delle situazioni nelle le quali sarebbe estremamente comodo se non necessario violare tale vincolo.
Valga per tutte il caso di una lettura di un’immagine da Flickr. In ogni caso può sempre essere utile poter reperire dati da un dominio diverso specialmente quando si ha la possibilità di modificare il codice del client ma non quello del server.
Esiste però la possibilità di aggirare l’ostacolo sfruttando il tag <script> usato per caricare i file javascript. Infatti per tale tag non esiste nessun vincolo per il dominio di provenienza.
Precondizione per l’uso di questa tecnica è l’uso di JSON per incapsulare i dati, ma questo non è davvero un problema in quanto tale notazione è ormai uno standard nel dialogo client-server.
Il trucco è veramente geniale.
Il dominio sia:

http://www.altrodominio.org

il JSON da leggere:

{
"cognome": "Bruno",
"nome": "Giordano",
"datanasc": "01-01-1548",
"sesso": "m",
"luogonasc": "Nola"
}

Il server incapsula il JSON come argomento di una funzione “FnEsempio”

FnEsempio({
"cognome": "Bruno",
"nome": "Giordano",
"datanasc": "01-01-1548",
"sesso": "m",
"luogonasc": "Nola"
});

Funzione di CallBack che ha come argomento i dati in formato JSON.
Fate attenzione che la funzione, purtroppo, deve essere globale.

FnEsempio = function (data) {
alert(data);
/*
o quello che diavolo volete voi
*/
};

script creato dinamicamente .

var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src","http://www.altrodominio.org/jsonp_esempio");
document.head.appendChild(script);
document.head.removeChild(script);

Se il server usa una sua funzione di CallBack bisogna conoscerne il nome ed
utilizzare quello.
Se previsto, come nelle API di Flickr, è possibile passare come parametro al server il nome della vostra funzione di CallNack.
Se la funzione si chiamaFnMia l’URL diventa:

script.setAttribute("src","http://www.altrodominio.org/jsonp_esempio?jsoncallback=FnMia");

Il meccanismo è molto semplice: quando viene caricato lo script è eseguita la funzione di CallBack alla quale è passato come argomento il JSON che contiene i dati. Quindi  all’interno di tale funzione, da voi implementata,  avrete a vostra diposizione  i dati.
Non è necessario scrivere tutto il codice usato sopra nell’esempio. Una soluzione è disponibile in jQuery e la trovate nel file getjson.js :

$.ajax({
type: 'GET',
cache: false,
url: www.altrodomnio.org,
dataType: 'jsonp',
contentType: "application/json",
jsonpCallback: FnMia,
data: params,
success: fnOk,
error: fnErr
});

Una soluzione che funziona con la stessa logica ma non utilizza jQuery la trovate nel file uajsonp.js:

var UaJSONP = {
  load: function(url) {
  var script = document.createElement("script");
  script.setAttribute("type", "text/javascript");
  script.setAttribute("src", url);
  document.head.appendChild(script);
  document.head.removeChild(script);
  },
  call: function(url, callBack, fnOk) {
  eval(callBack + '=function(data){fnOk(data);' + callBack + '=null;}');
  UaJSONP.load(url);
  }
};

Infine vi propongo un’altra soluzione che ha il difetto di non essere standard rispetto alle API di siti tipo Flickr ma che è forse più semplice (questa è la mia impressione). Per quanto la cosa non sia rilevante credo anche che sia originale. Invece di incapsulare il JSON come argomento di una funzione, lo si trasforma in variabile con un  nome. Dato il solito JSON:

{
"cognome": "Bruno",
"nome": "Giordano",
"datanasc": "01-01-1548",
"sesso": "m",
"luogonasc": "Nola"
}

Diventa:

var nomeEsempio={
"cognome": "Bruno",
"nome": "Giordano",
"datanasc": "01-01-1548",
"sesso": "m",
"luogonasc": "Nola"
}

Vi faccio notare che è meno invasiva la modifica del JSON ma soprattutto che NON è necessario usare una variabile globale come nel caso di una funzione di CallBack. Il codice di questa soluzione lo rovate nel file uajsonp2.js.

var UaJSONP2 = {
    get: function(url, jsonName, fnCall) {
        this.fnCall = fnCall;
        this.jsonName = jsonName;
        var script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        script.setAttribute("onload", "UaJSONP2.callback()");
        script.setAttribute("src", url);
        document.head.appendChild(script);
        document.head.removeChild(script);
    },
    callback: function() {
        var f = new Function("pars", "return " + this.jsonName + ";");
        this.fnCall(f());
    }
};

Nell’esempio es11 il file es11.json:

var jsondata = {
    "esempio": "es11",
    "cognome": "Martini",
    "nome": "Roberto",
    "datanasc": "24-02-1980",
    "sesso": "m",
    "luogonasc": "Firenze"
}

Codice javascript:

var callback = function (data) {
                 console.log(data);
                };
UaJSONP2.get('http://127.0.0.1:8081/es11.json', 'jsondata', callback);

Gli esempi (uajsonp_es.tar.gz) non sono molto commentati e la grafica è spartana, ma sono contemplati diversi casi sia per quanto riguarda la soluzione adottata sia per la tipologia di dati; inoltre il codice è semplice. Gli esempi es01 e es10 utilizzano codice javascript senza le librerie, per meglio evidenziare la tecnica usata; es07 si connette a Flickr. Per provare gli esempi è disponibile un banale server in python chiamato con due porte diverse dagli script server8080.sh e server8081.sh (la roba in bat e cmd potete farvela da soli).