仅当包含突出显示的匹配项时才在搜索结果模板中显示属性

Show attribute in search result template only if contains highlighted matches

我有几个属性设置为 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 显示的内容,一种 文本 blob 带省略号的文本包含这些属性的标记词。

这可能吗?我正在使用 algolia instasearch.js,谢谢!

更新

感谢 的回答,不幸的是,一小部分代码在我的案例中不起作用,具体来说:

['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';
};

首先,为了在继续之前澄清索引的设置,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 参数来访问 and/or 修改传递给模板的数据。

在这个具体的例子中,我们想看看 transformData.item on the hits widget

第一步是记录数据:

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 属性。如果你真的想要信息,你可以选择在 attributesToSnippetattributesToHighlight 中设置它。

但是,对于您的用例,我们只需要 matchLevel。我们想要的是仅在 matchLevel !== 'none' 时显示元素。不幸的是,Hogan.jsinstantsearch.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,你应该使用{{{ ... }}}而不是{{...}},我在这里替换了它们)