Instantsearch.js: customized hit widget new transformItems not highlighting

Created on 18 Feb 2019  路  5Comments  路  Source: algolia/instantsearch.js

Do you want to request a feature or report a bug? Not sure.

What is the current behavior?

We have customized the hits widget with a transformItems function. The transformItems function splits our descriptionTruncated attribute on the first \n and displays the content above the split in one div (subhead) and the content after the split in a separate div (description) in our hits results template.

In our hits template, if we specify the attribute only within our div (ex: {{{subhead}}}) then it displays perfectly but, of course, we have not told it to highlight. We want it to highlight.

If we specify the highlight result, (ex: {{{_highlightResult.subhead.value}}} in the hits template, then those fields show up blank in our results.

We tried the helper using the v3 documentation and that also returned blank results (ex. {{#helpers.highlight}}{ "attribute": "subhead" }{{/helpers.highlight}})

What is the expected behavior?

We expect to be able to highlight the hit result in the new transformed items we've created.

Here is the entire customized widget:

search.addWidget(
     instantsearch.widgets.hits({
       container: '#hits',
           transformItems(items) {
            return items.map(item => {
                var parseDescription = item.descriptionTruncated.split("\n");               
                var summary = parseDescription[0];
                var description = parseDescription[1];


                return {
                                   ...item,
                                   description: description,
                                   summary: summary
                                }
            });
       },
       templates: {
         item: '<div class="hit">' +
                           '    <div class="hit-content" style="padding-bottom: 2em;">' +
                           '        <a href="{{{Url}}}" class="hit-name">{{{_highlightResult.title.value}}}<\/a>' +
                           '        <div style="height:5px;"><\/div>' +
                           '       <div class="hit-description" style="font-size: normal;"> <span style="font-weight: bold;">Inventors:</span> {{{finalPathInventors}}}<\/div>' +
                           '       <div style="height:0px;"><\/div>' +
                           '        <span class="hit-description" style="font-weight: bold;">Subhead:<\/span><span>{{{_highlightResult.subhead.value}}}<\/span>' +
                           '        <div style="height:5px;"><\/div>' +
                           '        <span class="hit-description" style="font-weight: bold;">Description: <\/span><span>{{{_highlightResult.description.value}}}<\/span>' +
                           '        <div style="height:5px;"><\/div>' +
                           '        <div class="hit-description" style="font-size: normal;"><span style="font-weight: bold;">Categories:<\/span> {{{finalPathCategories}}} <\/div>' +
                           '        <div style="height:5px;"><\/div>' +
                           '    <\/div>' +
                           '<\/div>'
                       },
                   })
                   );

And here is the orginal widget before customization, which, of course, highlights the descriptionTruncated just fine:

search.addWidget(
     instantsearch.widgets.hits({
       container: '#hits',
       templates: {
         item: '<div class="hit">' +
                           '    <div class="hit-content" style="padding-bottom: 2em;">' +
                           '        <a href="{{{Url}}}" class="hit-name">{{{_highlightResult.title.value}}}<\/a>' +
                           '        <div style="height:5px;"><\/div>' +
                           '       <div class="hit-description" style="font-size: normal;"> 
                           '        <span class="hit-description" style="font-weight: bold;">Summary: <\/span><span>{{{_highlightResult.descriptionTruncated.value}}}<\/span>' +
                           '        <div style="height:5px;"><\/div>' +
                           '        <div class="hit-description" style="font-size: normal;"><span style="font-weight: bold;">Categories:<\/span> {{{finalPathCategories}}} <\/div>' +
                           '        <div style="height:5px;"><\/div>' +
                           '    <\/div>' +
                           '<\/div>'
                       },
                   })
                   );
Question

All 5 comments

If I understand your question correctly, you are creating a new key within the "hit" object and want to use that for highlighting. However, the highlighting happens in the Algolia engine, and not frontend.

To have a highlighted value, you'll need to set _highlightResults[yourNewKey].value = transformOrSomething(_highlightResults[yourOldKey].value).

Hope that makes sense!

If I understand your question correctly, you are creating a new key within the "hit" object and want to use that for highlighting. However, the highlighting happens in the Algolia engine, and not frontend.

To have a highlighted value, you'll need to set _highlightResults[yourNewKey].value = transformOrSomething(_highlightResults[yourOldKey].value).

Hope that makes sense!

Thank you so much for your response. Really appreciate it.

In transformItems we are not able to access the _highlightResults.

Where should we put _highlightResults[yourNewKey].value = transformOrSomething(_highlightResults[yourOldKey].value)?

The transformItems would look something like this:

    transformItems(items) {
      return items.map(item => {
        item._highlightResult.fakeName = {
          value: item._highlightResult['name'].value.toLocaleUpperCase(),
        };
        return item;
      });
    },

In this case my transform is making the value uppercase, I think in your case you want to trim, but I'm not fully sure from your code sample what the goal was.

Edit instantsearch.js-app

The transformItems would look something like this:

    transformItems(items) {
      return items.map(item => {
        item._highlightResult.fakeName = {
          value: item._highlightResult['name'].value.toLocaleUpperCase(),
        };
        return item;
      });
    },

In this case my transform is making the value uppercase, I think in your case you want to trim, but I'm not fully sure from your code sample what the goal was.

Edit instantsearch.js-app

Thank you!

Yeah, we tried a whole bunch of different things, including the example above. I'll try and be more clear of our goal: We had an attribute, descriptionTruncated, which the first string of text is the summary/subhead, then there is a line break (we had /n in the descriptionTruncated attribute in our json file) and then, following the line break is another string (the description). We wanted to display those two strings in separate divs in our hits template, and then have both of those separate divs highlighted when we typed in the search box.

We ended up using a Hogan helper. Anyway, it does what we need it to do. It displays the subhead in a separate div and then highlights the separate divs like it would with a normal widget.

hits({
  transformItems(items) {
    return items.map(item => {
      return {
        ...item,
        parseSummary: function() {
          return function(text) {
            return Hogan.compile(text)
              .render(this)
              .split("\n")[0];
          };
        },
        parseDescription: function() {
          return function(text) {
            var split = Hogan.compile(text)
              .render(this)
              .split("\n");
            return split[split.length - 1];
          };
        }
      };
    });
  },
  templates: {
    item:
      '<div class="hit">' +
      '    <div class="hit-content" style="padding-bottom: 2em;">' +
      '        <a href="{{{Url}}}" class="hit-name">{{{_highlightResult.title.value}}}</a>' +
      '        <div style="height:5px;"></div>' +
      '        <h1 class="hit-description" style="font-weight: bold; font-size: 1em;"></span><span>{{#parseSummary}}{{{_highlightResult.descriptionTruncated.value}}}{{/parseSummary}}</h1>' +
      '        <div style="height:5px;"></div>' +
      '        <div class="hit-description" style="color: #505050;"><span style="font-weight: bold; color: #000;">Summary: </span><span>{{#parseDescription}}{{{_highlightResult.descriptionTruncated.value}}}{{/parseDescription}}</span>' +
      '        <div style="height:5px;"></div>' +
      '        <div class="hit-description" style="font-size: normal; color: #505050;"><span style="font-weight: bold; color: #000;">Categories:</span> {{{finalPathCategories}}} </div>' +
      '        <div style="height:5px;"></div>' +
      "    </div>" +
      "</div>"
  }
});

Extraneous info....the syntax was important in the hits template because, at first, we only had two brackets around our highlightResults so it was highlighting but stripping the highlight style (It was putting mark tags around the highlighted values. Once we put the extra bracket around the highlightResults, the expected styling came back.

Good to know you found a solution, and sorry for initially misunderstanding what the goal you were trying to solve was.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ChristopherDosin picture ChristopherDosin  路  4Comments

nicosrugeris picture nicosrugeris  路  3Comments

francoischalifour picture francoischalifour  路  3Comments

zeke picture zeke  路  3Comments

jvreeken picture jvreeken  路  3Comments