Standardizzare la struttura dei dati per un layout di contenuto

Lo sviluppatore del layout di contenuto deve standardizzare la struttura dei dati che il layout di contenuto riceve.

Se tutti i dati sono presenti, il layout di contenuto potrà eseguire il rendering del componente senza ulteriori operazioni. Se invece non tutti i dati sono presenti, il layout potrebbe dover eseguire query aggiuntive. In tutti i casi il layout di contenuto non deve mai supporre un determinato formato dati, ma deve forzare i dati in un formato che consentirà il rendering.

Sarà quindi necessario assicurarsi di disporre di tutti i dati previsti. Se i dati non esistono, sarà necessario eseguire query aggiuntive. Potenzialmente potrebbe mancare nei dati i campi seguenti:

  • la voce "fields" per i campi di riferimento

  • campi di testo di grandi dimensioni

Poiché i layout di contenuto sono progettati per tipi di contenuto specifici, lo sviluppatore di un layout di contenuto conosce la lista dei campi necessari. I dati devono essere recuperati per ognuno di questi campi in modo che il layout di contenuto possa eseguire il rendering. Sono disponibili due opzioni: recuperare i dati mancanti e quindi eseguire il rendering con i dati completi oppure eseguire immediatamente il rendering e quindi recuperare i dati mancanti per riempire gli spazi vuoti.

Opzione 1: recuperare i dati mancanti, quindi eseguire il rendering con dati completi

Creare una promessa per recuperare i dati necessari, quindi continuare il rendering quando tutte le promesse restituiscono i dati.

Si supponga, ad esempio, di disporre dei tipi di contenuto seguenti con i campi corrispondenti:

  • starter-blog-author

    • campi

      • starter-blog-author_name: campo di testo

      • starter-blog-author_bio: campo di testo

  • starter-blog-post

    • campi

      • starter-blog-post_title: campo di testo

      • starter-blog-post_content: campo di testo di grandi dimensioni

      • starter-blog-post_author: riferimento a un elementostarter-blog-author

Il layout di contenuto contiene il modello seguente per eseguire il rendering di questi valori di campo previsti:

{{#fields}}
<div class="blog_container">
    <div class="blog-post-title">{{starter-blog-post_title}}</div>
    {{#starter-blog-post_author.fields}}
    <div class="blog-author-container">
        <div class="blog-author-details">
            <div class="blog-author-name">{{starter-blog-author_name}}</div>
            <div class="blog-author-bio">{{{starter-blog-author_bio}}}</div>
            <span class="more-from-author">More articles from this author</span>
        </div>
    </div>
    {{/starter-blog-post_author.fields}}
    <div class="blog-post-content">{{{starter-blog-post_content}}}</div>
</div>
{{/fields}}

Il layout di contenuto può essere richiamato con i dati dalle query riportate di seguito.

  • Query elemento con "expand" - tutti i dati forniti

    • /content/published/api/v1.1/items/{id}?expand=fields.starter-blog-post_author&channelToken=8dd714be0096ffaf0f7eb08f4ce5630f

    • Questo è il formato dei dati necessario per popolare in modo corretto tutti i valori nel modello. Se viene utilizzata una qualsiasi delle altre query, sarà necessario ulteriore lavoro per recuperare i dati e convertirli in questo formato.

    • "fields": {    
          "starter-blog-post_title": "...",
          "starter-blog-post_summary": "...",
          "starter-blog-post_content": "...",
          "starter-blog-post_author": {
              "id": "CORE386C8733274240D0AB477C62271C2A02",
              "type": "Starter-Blog-Author"
              "fields": {
                  "starter-blog-author_bio": "...",
                  "starter-blog-author_name": "..."
              }
          }
      }
  • Query elemento senza "expand" - campi degli elementi di riferimento "starter-blog-post_author.fields" mancanti:

    • /content/published/api/v1.1/items/{id}?channelToken=8dd714be0096ffaf0f7eb08f4ce5630f
    • "fields": {    
          "starter-blog-post_title": "...",
          "starter-blog-post_summary": "...",
          "starter-blog-post_content": "...",
          "starter-blog-post_author": {
              "id": "CORE386C8733274240D0AB477C62271C2A02",
              "type": "Starter-Blog-Author"
          }
      }
  • Query SCIM - campo di testo di grandi dimensioni "starter-blog-post_content" mancante, campi degli elementi di riferimento "starter-blog-post_author.fields" mancanti:

    • /content/published/api/v1.1/items?q=(type eq "Starter-Blog-Post")&fields=ALL&channelToken=8dd714be0096ffaf0f7eb08f4ce5630f

    • "fields": {
          "starter-blog-post_title": "...",
          "starter-blog-post_summary": "...",
          "starter-blog-post_author": {
              "id": "CORE386C8733274240D0AB477C62271C2A02",
              "type": "Starter-Blog-Author"
          }
      }

Per eseguire il rendering in modo coerente con una qualsiasi di queste query, il file render.js del layout di contenuto deve poter determinare che tutti i campi di riferimento vengano espansi e che i campi di testo di grandi dimensioni siano presenti.

Se così non fosse, dovrebbe eseguire nuove query sui campi, correggere i dati e quindi eseguire il rendering con i dati completi.

Funzione render() di esempio:

render: function (parentObj) {
    var self = this,
        template,
        contentClient = self.contentClient,
        content = self.contentItemData;

     var getRefItems = function (contentClient, ids) {
        // Calling getItems() with no "ids" returns all items.
        // If no items are requested, just return a resolved Promise.
        if (ids.length === 0) {
            return Promise.resolve({});
        } else {
            return contentClient.getItems({
                "ids": ids
            }); 
        }
     };
   
     var fetchIDs = [], // list of items to fetch
         referedFields = ['starter-blog-post_author'], // names of reference fields
         largeTextFields = ['starter-blog-post_content'], // large text fields in this asset
         fieldsData = content.fields;
     // See if we need to fetch any referenced fields
     referedFields.forEach(function (fieldName) {
         if(fieldsData[fieldName] && fieldsData[fieldName].fields) {
            // got data already, nothing else to do
         } else { 
             // fetch this item
             fetchIDs.push(fieldsData[fieldName].id);
         }
     });

     // See if we need to fetch any large text fields
     for(var i = 0; i < largeTextFields.length; i++) {
        if(!fieldsData[largeTextFields[i]]) {
           // need to fetch this content item directly to get all the large text fields
            fetchIDs.push(content.id);
            break;
        }
     }
    // now we have the IDs of all the content items we need to fetch, get them all before continuing
    getRefItems(contentClient, fetchIDs).then(function (referenceData) {
        var items = referenceData && referenceData.items || [];

        // add the data back in
        items.forEach(function (referencedItem){
            // check if it's the current item
            if(referencedItem.id === content.id) {
               // copy across the large text fields 
               largeTextFields.forEach(function (fieldName) {
                   fieldsData[fieldName] = referencedItem.fields[fieldName];
                });
            } else{
                // check for any referenced fields
                for (var i = 0; i < referedFields.length; i++) {
                    if(referencedItem.id === fieldsData[referedFields[i]].id){
                       // copy across the fields values
                       fieldsData[referedFields[i]].fields = referencedItem.fields;
                       break;
                    }
                }
            }
        });

        // now data is fixed up, we can continue as before
        try{
           // Mustache
           template = Mustache.render(templateHtml, content);

             if(template) {
                $(parentObj).append(template);
             }

        } catch (e) {            
            console.error(e.stack);
        }    
    });
}

Opzione 2: eseguire immediatamente il rendering, quindi recuperare i dati mancanti per riempire gli spazi vuoti

Separando gli elementi che potrebbero non essere presenti ed eseguendone il rendering in un secondo momento è possibile migliorare le prestazioni. Saranno necessari due modelli Mustache, il primo per eseguire il rendering iniziale, lasciando "spazi vuoti" che verranno riempiti con il secondo rendering eseguito con i dati completi.

Ciò richiede l'impostazione del modello Mustache per supportare più passaggi, con modelli distinti per gli "spazi vuoti" oppure con le macro del modello di restituzione al posto dei valori effettivi. In entrambi i casi sarà necessario "nascondere" gli spazi vuoti finché i dati non saranno stati recuperati, quindi popolarli e visualizzarli con l'animazione dell'interfaccia utente appropriata per evitare troppi spostamenti erratici nella pagina.