Insert Items into Hits

I’d like to insert some items into my Algolia hits (e.g. an image after every fourth hit, or for specific hits to use a different template altogether), and preferably have them rendered through the hits widget. I think a good way to do it would be using the templates property, like so:

/* Results */
const searchHits = instantsearch.widgets.hits({
  container: '#search-results',
  templates: {
  	empty: '<b>No results.</b>',
  	item: function(item) {
      if(item.condition === true) {
        return document.getElementById('result-template').innerHTML;
      } else {
        return document.getElementById('result-template-alt').innerHTML;
      }
  }, 
  ...
}

This does not work how I would expect it to, however. Whatever function is normally run on the templates is not run in this case, and any mustache notation is left in its original form. Expected result:

item: {name: "Fred", age: 22}
<div>Hey, Fred!</div>

Actual result:

item: {name: "Fred", age: 22}
<div>Hey, {{name}}!</div>

I think an alternative method that would work would be to create a single template with some conditions. However, I think this is a much less clean way to go about it and so I would like to avoid it.

{{#regularHit}}
  <div>Hey, {{name}}!</div>
{{/regularHit}}
{{^regularHit}}
  <div>Goodbye, {{name}}!</div>
{{/regularHit}}

Hey Kevin,

That’s correct, in InstantSearch you have two choices:

  1. use the template, in which case it needs to be a string
  2. use direct html, without template, in which case it needs to be a function

Because we do the distinction like that, it means you have to choose to either use a complete template, and do logic in there, either choose function and do all your logic (and html sanitation) in JS.

Hope that makes it clearer!

It does, thank you.

Is this a good solution, or is there a better way to insert results into my hits? For example, if I wanted to insert an image after every fourth result?

1 Like

You can also use transformItems to add those images as if they were hits by using regular array methods (splice should work here). Otherwise your options work fine :slight_smile:

1 Like

I like the transformItems method. But doesn’t that lead me to the same problem?

transformItems returns the items array, which is the array of hit Objects. Splicing an <img ... /> tag into that array does not work. The items seem to need a template to be placed into.

Oops, sorry for not being fully clear. Here’s a demo that shows what I meant:

Note that the hitsPerPage being set (now 20) will get augmented by 20 / 4 (so there will be 25 hits per page).

1 Like

I’ve also once made a more advanced version (for Vue InstantSearch, but with a strategy which also works for InstantSearch.js) where hits from another index are injected.

See that sandbox here:

1 Like

Ah okay, I misunderstood. So in that first example, it looks like you’re doing the ‘alternative method’ from my original post.

The second one is much harder to understand, especially since I’m not familiar with Vue. It does look useful for another use-case of mine, though: I want to pull ‘featured results’ from a separate index and have them appear as the first three results. I’ll spend some time trying to understand the code.

Also: https://codesandbox.io is a very pretty editor. I like it.

Here’s a version of the second injection of a different index in InstantSearch.js:

And yes, as explained in my first answer, either you use the string form and do it like that, either you do the function form and don’t use any Hogan templating at all. In what I made I did the injection with transformItems, but in the template I still need to check if something is injected or not, since it has different dom. If your injected items look exactly the same as your original items, it’s not necessary to do that conditional in the template

1 Like