內容版面配置的資料結構標準化

內容版面配置開發人員需要將內容版面配置接收的資料結構標準化。

假如全部的資料都存在,內容版面配置可以只呈現元件。如果資料未全數存在,內容版面配置可能需要進行額外的查詢。在所有情況下,內容版面配置都不應假設使用某一特定資料格式,而是應強制讓資料轉換成可呈現的格式。

您需要確保所有想要的資料都存在。如果資料不存在,您將需要進行額外的查詢。資料中可能會遺漏的欄位如下:

  • 參照欄位的 "fields" 項目

  • 大量文字欄位

內容版面配置都是針對特定內容類型所設計,因此內容版面配置的開發人員知道所需的欄位清單。系統必須擷取這些欄位的資料,內容版面配置才能夠呈現。您有以下的兩個選項:擷取遺漏的資料,然後呈現完整資料;或者,立即呈現,再擷取遺漏的資料來填入空白區域。

選項 1:擷取遺漏的資料,然後呈現完整資料

建立一個擷取所需資料的承諾,然後當所有承諾傳回時繼續呈現。

例如,以下列的內容類型與相對應的欄位為例:

  • starter-blog-author

    • 欄位

      • starter-blog-author_name - 文字欄位

      • starter-blog-author_bio - 文字欄位

  • starter-blog-post

    • 欄位

      • starter-blog-post_title - 文字欄位

      • starter-blog-post_content - 大量文字欄位

      • starter-blog-post_author - starter-blog-author 項目的參照

內容版面配置使用以下樣板呈現這些預期的欄位值:

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

可使用下列查詢中的資料呼叫內容版面配置:

  • 含 "expand" 的項目查詢 - 提供所有資料

    • /content/published/api/v1.1/items/{id}?expand=fields.starter-blog-post_author&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"
              "fields": {
                  "starter-blog-author_bio": "...",
                  "starter-blog-author_name": "..."
              }
          }
      }
  • 不含 "expand" 的項目查詢 - 沒有參照的項目欄位 "starter-blog-post_author.fields"

    • /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 查詢 - 沒有大量文字欄位 "starter-blog-post_content"、沒有參照的項目欄位 "starter-blog-post_author.fields"

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

為了讓這些查詢的呈現一致,內容版面配置的 render.js 必須確定所有的參照欄位都展開且大量文字欄位存在。

若沒有的話,就必須往回查詢這些欄位、修正資料,然後呈現完整的資料。

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

選項 2:立即呈現,再擷取遺漏的資料來填入空白區域

將可能不存在的項目分離出來,然後在第二次傳送時呈現這些項目,以讓效能獲得提升。這將需要用到兩個 Mustache 樣板,第一個執行最初的呈現並將「空洞」留下,待資料完備後再於第二次呈現時填入。

這需要將 Mustache 樣板設定為支援多次傳送,其方式有兩種:為「空洞」提供個別的樣板,或讓模型傳回樣板巨集,而非實際值。無論是哪一種方式,在擷取到資料並接著將資料填入空洞以透過適當的 UI 動畫顯示之前,您都需要先將這些空洞隱藏起來,以免頁面不停地「跳動」。