Sempre più spesso i siti web caricano dati nella pagina in modo asincrono, ad esempio quando i dati sono paginati.

Questa gestione può essere con dei framework quali JQuery, Angular, React, ecc..

Se però l'esigenza è solo quella di renderizzare dell'html, si può utilizzare un altro approccio usando solo JavaScript senza scaricare pesanti librerie.

Per prima cosa va inserito in pagina un placeholder dove verrà inserito l'html caricato in modo asincrono:

HTML

<div id="wrapper-esempio-1"></div>

Un possibile approccio gestire i dati è questo, dove l'html viene generando concatenando delle stringhe che rappresentano i template l'html risultante:

JavaScript

function example1() {
  // id dell'elemento html in cui verrà inserito l'html risultante
  var elementId = 'wrapper-esempio-1';
  var element = document.getElementById(elementId);

  element.innerHTML = 'Attendi ...';

  sgart.jsonGet('./sgart-template-examples.json', function (response) {
    // renderizzo i template con i dati
    var s = '';
    // ciclo su ogni elemento del json ritornato e renderizzo gli item
    response.forEach(function (value, index) {
      var flagOdd = index % 2 === 1; // gestisco una classe diversa per le righe pari e dispari

      // aggiungo gli items
      s += '<li class="item item-1 ' + (flagOdd ? 'odd' : 'even') + '">'
        + '<a href="' + value.url + '">'
        + ' | ' + index + ' - <strong>' + value.title.htmlEncode() + '</strong> |'
        + '</a>'
        + '</li>'
    });
    // unisco i due template
    var sComplete = '<div class="container-main">'
      + '<h4>Esempio solo JavaScript</h4>'
      + '<ul>' + s + '</ul>'
      + '</div>';

    // scrivo l'html risultate nella pagina
    element.innerHTML = sComplete;
  });
}
pur funzionando perfettamente presenta alcune limitazioni:
  • l'html risultante non è molto leggibile
  • con template html più complessi la leggibilità peggiora
  • va gestito l'escape delle virgolette singole o doppie quando il testo viene inserito negli attributi
  • va gestito l'escape dei caratteri maggiore o minore quando questi fanno parte del testo da visualizzare

Per sopperire a queste limitazioni si può implementare un semplice gestore di template html.

In questo caso il template html viene inserito nella pagina all'interno di alcuni tag script, con l'accortezza di impostare l'attributo type a text/template:

HTML

<div id="wrapper-esempio-2"></div>

<script id="template-main" type="text/template">
  <div class="container-main">
    <h4>Esempio con template</h4>
    <ul>
      {{items}}
    </ul>
  </div>
</script>

<script id="template-item-1" type="text/template">
  <li class="item item-1 {{class}}">
    <a href="{{url}}">{{sep}}{{index}} - <strong>{{title}}</strong>{{sep}}</a>
  </li>
</script>
per convenzione uso le doppie parentesi graffe per racchiudere le parti che fungeranno da placeholder (o tag) in cui verranno sostituiti i valori

A questo punto serve solo una piccola libreria JavaScript con le funzioni per gestire i template. Le funzioni sono:
  • sgart.getTemplate: per leggere il template dalla pagina e convertirlo in stringa
  • String.prototype.replaceTag...: per sostituire i tag nel template presenti nella foma {{nomeTag}}
  • String.prototype.htmlEncode: per fare l'escape del testo html e delle virgolette doppie e singole
  • String.prototype.attrEncode: per fare l'escape solo delle virgolette doppie e singole
  • String.prototype.writeToHtml: come helper per scrivere l'html risultante
il codice della libreria è questo:

JavaScript

"use strict";
var sgart = sgart || {};

// legge il template dalla pagina html identifiato da uno specifico "id"
sgart.getTemplate = function (templateId) {
  var element = document.getElementById(templateId);
  if (element === null) {
    throw new Error("Html template with id \"" + templateId + "\" not found.");
  }
  return element.innerHTML;
};

// sostituisce un TAG senza applicare nessun escape
String.prototype.replaceTag = function (tagName, value) {
  var re = new RegExp("\{\{" + tagName + "\}\}", "gi");
  return this.replace(re, value);
};

// sostituisce un TAG facendo l'escape delle virgolette singole e doppie
String.prototype.replaceTagAttr = function (tagName, value) {
  var re = new RegExp("\{\{" + tagName + "\}\}", "gi");
  return this.replace(re, value.attrEncode());
};

// sostituisce un TAG facendo l'encoding HTML + l'escape delle virgolette singole e doppie
String.prototype.replaceTagHtml = function (tagName, value) {
  var re = new RegExp("\{\{" + tagName + "\}\}", "gi");
  return this.replace(re, value.htmlEncode());
};

// encode dei caratteri in html
String.prototype.htmlEncode = function () {
  var node = document.createTextNode(this);
  return document.createElement("a").appendChild(node).parentNode.innerHTML.replace(/'/g, "&#39;").replace(/"/g, "&#34;");
};

// encode delle virgolette singole e doppie
String.prototype.attrEncode = function () {
  return this.replace(/'/g, "&#39;").replace(/"/g, "&#34;");
};

// scrive la stringa nell'elemento html identificato da un "id"
String.prototype.writeToHtml = function (elementId) {
  var element = document.getElementById(elementId);
  if (element === null) {
    throw new Error("Html element with id \"" + elementId + "\" not found.");
  }
  element.innerHTML = this;
};
a questo punto l'esempio iniziale diventa:

JavaScript

function example2() {
  // id dell'elemento html in cui verrà inserito l'html risultante
  var elementId = "wrapper-esempio-2";

  "Attendi ...".writeToHtml(elementId);

  sgart.jsonGet("./sgart-template-examples.json", function (response) {
    // recupero i template
    var sTemplateMain = sgart.getTemplate("template-main");
    var sTemplateItem = sgart.getTemplate("template-item-1");

    // renderizzo i template con i dati
    var s = '';
    response.forEach(function (value, index) {
      var flagOdd = index % 2 === 1;

      // aggiungo gli items
      s += sTemplateItem
        .replaceTag("class", flagOdd ? "odd" : "even")
        .replaceTag("sep", " | ")
        .replaceTag("index", index + 1)
        .replaceTagHtml("title", value.title)
        .replaceTagAttr("url", value.url);
    });
    // unisco i due template
    var sComplete = sTemplateMain.replaceTag("items", s);

    // scrivo l'html risultate nella pagina
    sComplete.writeToHtml(elementId);
  });

}
Come si vede il codice JavaScript risulta più leggibile, ma soprattutto è più semplice capire qual'é l'html risultante in quando è visibile in pagina all'interno dei tag script.
Anche la manutenzione successiva oppure l'uso di template più comlessi è resa più agevole da questo approccio.

Per l'esempio ho utilizzato questo file json ./sgart-template-examples.json:

JavaScript

[
  {
    "title": "Animazione di elementi HTML con CSS3",
    "url": "https://www.sgart.it/IT/informatica/animazione-di-elementi-html-con-css3/post"
  },
  {
    "title": "SharePoint: Errors were found when compiling the workflow.",
    "url": "https://www.sgart.it/IT/informatica/sharepoint-errors-were-found-when-compiling-the-workflow/post"
  },
  {
    "title": "Generare un certificato self signed da PowerShell",
    "url": "https://www.sgart.it/IT/informatica/convertire-i-numeri-da-cifre-a-lettere-new/post"
  },
  {
    "title": "Prova con tag <a href=\"\">html</a>",
    "url": "https://www.sgart.it/IT/informatica/generare-un-certificato-self-signed-da-powershell/post"
  }
]
il risultato è questo:
Tags:
AJAX14 Esempi225 HTML74 HTML 554 JavaScript184 Vanilla JS24
Potrebbe interessarti anche: