Standardisera datastrukturen för en innehållslayout

Utvecklaren av innehållslayouten måste standardisera datastrukturen som innehållslayouten tar emot.

Om alla data finns med kan innehållslayouten helt enkelt återge komponenten. Om inte alla data finns med kan innehållslayouten behöva utföra ytterligare frågor. Under alla omständigheter ska innehållslayouten aldrig anta ett visst dataformat och i stället tvinga data till ett format som kan återges.

Du måste säkerställa att du har alla data som du förväntar dig. Om data inte finns måste du skapa de ytterligare frågorna. Följande fält kanske saknas i dessa data:

  • Posten "fields" för fält som det refereras till

  • Stora textfält

Eftersom innehållslayouter är utformade för specifika innehållstyper känner utvecklaren av innehållslayouten till listan över de fält som behövs. För vart och ett av dessa fält måste data hämtas så att innehållslayouten kan återges. Du har två alternativ att välja mellan: hämta data som saknas och sedan återge med fullständiga data eller återge omedelbart och sedan hämta data som saknas för att fylla i luckorna.

Alternativ 1: Hämta data som saknas och sedan återge med fullständiga data

Skapa ett löfte om hämtning av de data som krävs och fortsätt sedan med återgivningen när alla löften returneras.

Till exempel kan vi ha följande innehållstyper med motsvarande fält:

  • starter-blog-author

    • fält

      • starter-blog-author_name – textfält

      • starter-blog-author_bio – textfält

  • starter-blog-post

    • fält

      • starter-blog-post_title – textfält

      • starter-blog-post_content – stort textfält

      • starter-blog-post_author – referens till objektet starter-blog-author

Innehållslayouten har följande mall för att återge dessa förväntade fältvärden:

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

Innehållslayouten kan anropas med data från följande frågor:

  • Objektsfråga med "expand" – alla data angivna

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

    • Det här är det dataformat som krävs för att alla värden i mallen ska kunna fyllas i. Om någon av de andra frågorna används krävs ytterligare arbete för att hämta data och konvertera dem till det här formatet.

    • "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": "..."
              }
          }
      }
  • Objektsfråga, utan "expand" – objektsfälten "starter-blog-post_author.fields" som det refereras till saknas:

    • /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-fråga – det stora textfältet "starter-blog-post_content" saknas, fälten "starter-blog-post_author.fields" för objekt som det refereras till saknas:

    • /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 att kunna återge konsekvent med dessa frågor måste render.js från innehållslayouten kontrollera att alla fält som det refereras till expanderas och att de stora textfälten finns med.

Om så inte är fallet måste den fråga tillbaka om dessa, åtgärda data och sedan återge med fullständiga data.

Exempel på funktionen render():

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

Alternativ 2: Återge omedelbart och sedan hämta data som saknas för att fylla i luckorna

Prestanda kan förbättras genom att de objekt som kanske inte finns med skiljs ut och återges i en andra omgång. För detta krävs två Mustache-mallar, varav den första gör den första återgivningen, och lämnar "hål" som sedan fylls i med den andra återgivningen när data har blivit fullständiga.

För detta krävs att Mustache-mallen ställs in så att den stöder flera omgångar, antingen genom att ha separata mallar för "hålen" eller genom att låta modellen returnera mallmakron snarare än faktiska värden. I båda fallen måste du "dölja" de här hålen tills data har hämtats och sedan fylla i dem och visa dem med lämplig användargränssnittsanimering för att undvika att sidan "hoppar omkring" alltför mycket.