Разработчику макетов контента необходимо стандартизировать структуру данных, получаемых макетом контента.
Если присутствуют все данные, макет контента может просто визуализировать компонент. Если присутствуют не все данные, может потребоваться создать дополнительные запросы для макета контента. Во всех случаях макет контента никогда не должен принимать определенный формат данных, а вместо этого преобразовывать данные в формат, который будет визуализироваться.
Необходимо убедиться в наличии всех ожидаемых данных. Если данных нет, необходимо выполнить дополнительные запросы. Следующие поля могут отсутствовать в данных:
Запись "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 для поддержки нескольких проходов, используя отдельные шаблоны для "пустот", или используя макрокоманду шаблона возврата модели, а не фактических значений. В любом случае необходимо "скрыть" эти пустоты, пока данные не будут извлечены, а затем заполнить их и отобразить соответствующую анимацию пользовательского интерфейса, чтобы избежать слишком сильного "дерганья" страницы.