Показывать атрибут в шаблоне результатов поиска, только если он содержит выделенные совпадения

У меня есть несколько атрибутов, установленных как attributesToRetrieve. В моем шаблоне отображаются только некоторые из них. Примерно так:

<div id="results">
  <div>{{_highlightResult.attr1.value}}</div>
  <div>{{_highlightResult.attr2.value}}</div>
  <div>{{_highlightResult.attr3.value}}</div>
</div>

Таким образом, атрибуты будут отображаться в любом случае и выделяться, если они содержат совпадающее слово.

Теперь я хотел бы добавить еще один раздел, в котором могут отображаться все остальные атрибуты, но только если они содержат совпадающее слово, которое нужно выделить, например:

<div id="results">
  <div>{{_highlightResult.attr_1.value}}</div>
  <div>{{_highlightResult.attr_2.value}}</div>
  <div>{{_highlightResult.attr_3.value}}</div>
<!-- 
The following div will be rendered and displayed only 
if any of these special attributes contain an highlighted word. 
Only an attribute containing a matched word will be displayed 
-->
  <div class="other-attr">
    {{_highlightResult.Long_SpecialAttr_1.value}}
    {{_highlightResult.SpecialAttr_2.value}}
    {{_highlightResult.SpecialAttr_3.value}}
  </div>
</div>

Как упоминалось в комментарии, этот раздел будет отображаться и отображаться только в том случае, если какой-либо из этих специальных атрибутов содержит выделенное слово, также будет отображаться только атрибут, содержащий совпадающее слово.

Кроме того, как вы можете видеть, есть Long_SpecialAttr_1, это длинный текстовый атрибут, который я бы хотел, чтобы он отображался как атрибут фрагмента.

Чтобы дать лучшее представление (возможно), чего я пытаюсь добиться для этого дополнительного раздела, это что-то вроде одного отображения Google под каждым результатом поиска, своего рода текст text blob с многоточием, содержащим отмеченные слова. из этих атрибутов.

Это возможно? Я использую algolia instsearch.js, спасибо!

ОБНОВЛЕНИЕ

Спасибо @Jerska за его ответ, к сожалению, в моем случае не работал небольшой фрагмент кода, а именно:

['highlight', 'snippet'].forEach(function (type) {
  data['_' + type + 'Result'].forEach(function (elt) {
    elt.display = elt.matchLevel !== 'none';
  });
});

дает мне ошибку в консоли с указанием data._snippetResult.forEach() is undefined. Поэтому я изменил этот бит следующим образом:

for(var el in d._snippetResult)
{
  // create new property with bool value, true if not "none"
  d._snippetResult[el].display = d._snippetResult[el].matchLevel !== 'none';
};

person Gruber    schedule 30.04.2016    source источник


Ответы (1)


Прежде всего, просто чтобы уточнить настройки вашего индекса, прежде чем двигаться дальше, Algolia также выделяет атрибуты в attributesToSnippet.
Кроме того, чтобы отображать атрибуты во фрагменте с многоточием, можно установить snippetEllipsisText.
Возможно, вы захотите использовать эти настройки в своем индексе:

attributesToHighlight: ['attr_1', 'attr_2', 'attr_3', 'SpecialAttr_2', 'SpecialAttr_3'],
attributesToSnippet: ['Long_SpecialAttr_1:3'], // Snippet should contain max 3 words
snippetEllipsisText: '…' // This is the utf-8 "Horizontal ellipsis" character

Что касается внешнего интерфейса, в instantsearch.js вы можете использовать параметр transformData практически для любого виджета, чтобы получить доступ и/или изменить данные, переданные в шаблон.

В этом конкретном примере мы хотим взглянуть на transformData.item на hits виджете< /а>.

Первым шагом будет регистрация данных:

search.addWidget(
  instantsearch.widgets.hits({
    transformData: {
      item: function (data) {
        console.log(data);
        return data;
      }
    }
  })
);

Это позволит вам увидеть такой ответ:

_highlightResult: {
  attr_1: {
    value: 'lorem <em>ipsum</em> dolor <em>sit</em>',
    matchLevel: 'full',
    matchedWords: ['ipsum', 'sit']
  },
  attr_2: {
    value: 'lorem <em>ipsum</em> dolor',
    matchLevel: 'partial',
    matchedWords: ['ipsum']
  },
  attr_3: {
    value: 'lorem',
    matchLevel: 'none',
    matchedWords: []
  },
  // ...
},
_snippetResult: {
  Long_SpecialAttr_1: {
    value: 'lorem <em>ipsum</em> dolor …', // Let's assume Long_SpecialAttr_1 was equal to 'lorem ipsum dolor sit'
    matchLevel: 'full'
  }
}

К сожалению, здесь API немного непоследовательный, поскольку, как вы можете видеть, атрибуты фрагментов не имеют атрибута matchedWords, который есть у выделенных атрибутов. Вы можете установить его как в attributesToSnippet, так и в attributesToHighlight, если вам действительно нужна информация.

Однако для вашего варианта использования нам просто нужно matchLevel. Мы хотим отображать элементы, только если matchLevel !== 'none'. К сожалению, Hogan.js базовый механизм шаблонов instantsearch.js не обеспечивает большой гибкости, поэтому вы не могу просто поместить это сравнение в свой шаблон.

Решением может быть предварительное вычисление этих условий внутри transformData:

transformData: {
  item: function (data) {
    ['highlight', 'snippet'].forEach(function (type) {
      var group = data['_' + type + 'Result'];
      for (var attr in group) {
        if (!group.hasOwnProperty(attr)) continue;
        var elt = group[attr];
        elt.display = elt.matchLevel !== 'none';
      };
    });
    data.displaySpecial = false ||
      data._snippetResult.Long_SpecialAttr_1.display ||
      data._highlightResult.SpecialAttr_2.display ||
      data._highlightResult.SpecialAttr_3.display;
    return data;
  }
}

А затем используйте эти новые атрибуты в своем шаблоне:

<div id="results">
  <div>{{{_highlightResult.attr_1.value}}}</div>
  <div>{{{_highlightResult.attr_2.value}}}</div>
  <div>{{{_highlightResult.attr_3.value}}}</div>
<!-- 
The following div will be rendered and displayed only 
if any of these special attributes contain an highlighted word. 
Only an attribute containing a matched word will be displayed 
-->
  {{#displaySpecial}}
    <div class="other-attr">
      {{#_snippetResult.Long_SpecialAttr_1.display}}
        {{{_highlightResult.Long_SpecialAttr_1.value}}}
      {{/_snippetResult.Long_SpecialAttr_1.display}}

      {{#_highlightResult.SpecialAttr_2.display}}
        {{{_highlightResult.SpecialAttr_2.value}}}
      {{/_highlightResult.SpecialAttr_2.display}}

      {{#_highlightResult.SpecialAttr_3.display}}
        {{{_highlightResult.SpecialAttr_3.value}}}
      {{/_highlightResult.SpecialAttr_3.display}}
  </div>
  {{#displaySpecial}}
</div>

(Кстати, для рендеринга HTML нужно использовать {{{ ... }}} вместо {{...}}, здесь я их заменил)

person Jerska    schedule 30.04.2016
comment
Великолепно! большое спасибо за этот очень подробный ответ! :) У меня была небольшая проблема с forEach, ошибка консоли сообщила, что существует неопределенная функция (я думаю, потому что вы можете использовать forEach только для массивов, или я что-то пропустил?), поэтому я изменил этот бит, как указано в Обновить. - person Gruber; 01.05.2016
comment
О да, действительно, я принял свои мечты за реальность. ES5 forEach действительно не работает с объектами, тогда как функция underscore/lodash forEach работает. Я обновлю свой ответ. - person Jerska; 01.05.2016
comment
Понятно, но я думаю, что здесь действительно не хватает того, что я еще не использую Lodash: P - person Gruber; 01.05.2016