Datenstruktur für Inhaltslayouts standardisieren

Der Entwickler des Inhaltslayouts muss die Struktur der vom Inhaltslayout empfangenen Daten standardisieren.

Wenn alle Daten vorhanden sind, kann das Inhaltslayout die Komponente einfach rendern. Wenn nicht alle Daten vorhanden sind, muss das Inhaltslayout unter Umständen zusätzliche Abfragen senden. In keinem Fall darf das Inhaltslayout von einem bestimmten Datenformat ausgehen. Es muss stattdessen ein renderbares Format für die Daten erzwingen.

Stellen Sie sicher, dass alle erwarteten Daten vorhanden sind. Wenn sie nicht vorhanden sind, müssen Sie die zusätzlichen Abfragen senden. Die folgenden Felder können in den Daten fehlen:

  • Der "fields"-Eintrag für referenzierte Felder

  • Große Textfelder

Da Inhaltslayouts für spezielle Inhaltstypen entworfen werden, weiß der Entwickler eines Inhaltslayouts, welche Felder erforderlich sind. Für jedes dieser Felder müssen die Daten abgerufen werden, damit das Inhaltslayout gerendert werden kann. Ihnen stehen zwei Optionen zur Verfügung: Fehlende Daten abrufen und dann mit vollständigen Daten rendern oder sofort rendern und dann fehlende Daten abrufen, um Lücken zu füllen.

Option 1: Fehlende Daten abrufen und dann mit vollständigen Daten rendern

Erstellen Sie einen Promise, um die erforderlichen Daten abzurufen, und setzen Sie das Rendering dann fort, wenn alle Promises zurückgegeben wurden.

Beispiel mit den folgenden Inhaltstypen und den zugehörigen Feldern:

  • starter-blog-author

    • Felder

      • starter-blog-author_name - Textfeld

      • starter-blog-author_bio - Textfeld

  • starter-blog-post

    • Felder

      • starter-blog-post_title - Textfeld

      • starter-blog-post_content - großes Textfeld

      • starter-blog-post_author - Referenz zu einem starter-blog-author-Element

Das Inhaltslayout verwendet die folgende Vorlage zum Rendern dieser erwarteten Feldwerte:

{{#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}}

Das Inhaltslayout kann mit Daten aus den folgenden Abfragen aufgerufen werden:

  • Elementabfrage mit "expand" - alle Daten werden angegeben

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

    • Dieses Datenformat ist erforderlich, um alle Werte in der Vorlage erfolgreich aufzufüllen. Wenn eine der anderen Abfragen verwendet wird, müssen weitere Schritte ausgeführt werden, um die Daten abzurufen und in dieses Format zu konvertieren.

    • "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": "..."
              }
          }
      }
  • Elementabfrage ohne "expand" - referenzierte Elementfelder "starter-blog-post_author.fields" fehlen:

    • /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"
          }
      }
  • SCIM-Abfrage - großes Textfeld "starter-blog-post_content" fehlt, referenzierte Elementfelder "starter-blog-post_author.fields" fehlen:

    • /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"
          }
      }

Für ein konsistentes Rendering mit einer dieser Abfragen muss die Datei render.js aus dem Inhaltslayout sicherstellen, dass alle referenzierten Felder erweitert und die großen Textfelder vorhanden sind.

Andernfalls muss sie diese Felder erneut abfragen, die Daten korrigieren und dann das Rendering mit vollständigen Daten vornehmen.

render()-Beispielfunktion:

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);
        }    
    });
}

Option 2: Sofort rendern und dann fehlende Daten abrufen, um Lücken zu füllen

Sie können die Performance verbessern, indem Sie die eventuell nicht vorhandenen Elemente herausfiltern und in einem zweiten Durchgang rendern. Dazu sind zwei Mustache-Vorlagen erforderlich: Eine für das erste Rendering, bei dem "Lücken" verbleiben, die dann mit dem zweiten Rendering gefüllt werden, wenn die Daten vollständig sind.

Hierzu müssen Sie die Mustache-Vorlage so einrichten, dass sie mehrere Durchläufe unterstützt, entweder indem Sie separate Vorlagen für die "Lüken" verwenden oder festlegen, dass das Modell Vorlagenmakros anstelle tatsächlicher Werte zurückgibt. In jedem Fall müssen Sie diese Lücken "verbergen", bis die Daten abgerufen wurden, und sie anschließend füllen und mit geeigneter UI-Animation anzeigen, um ein übermäßiges "Herumspringen" der Seite zu vermeiden.