Showing "popular" items at top of a refinement list with instantsearch.js

G’day all,

One of my refinement lists, Designer, has about 250 items in it.

It’d be great if I could display the designers that I know are popular at the top of the list (say 6 designers) followed by a breaker, then the remaining designers beneath it in alphabetical order.

By “popular”, I don’t mean the ones with the most records/results against them. It is just the designers that I know are popular with our users based on website stats, emails received, social media comments/likes. It would be a static list of 6 designers that I could maintain manually.

I’ve tried specifying a custom javascript sort function using the refinementList options.sortBy parameter. This is what I did:

  • Had a hard-coded Javascript global array (popularDesigners) specifying the 6 designers
  • Created a javascript compareFunction that:
  • Checks if both a & b exist in popularDesigners - if they do, then compare the two using their index within the popularDesigners array
  • If only item a is in popularDesigners, rank it higher than b
  • If only item b is in popularDesigners, rank it higher than a
  • If neither a nor b are in popularDesigners, do a standard string comparison (e.g. a.name < b.name)
  • Specified the compareFunction as the sortBy parameter in the refinementList widget initialisation

This does the job, but by my calculation takes 350-400ms to run. I don’t think adding almost half a second to the page load time to provide this functionality is worth it. It will get even slower as the # of designers in the refinementList grows.

The breaker between the popular designers and the rest should be easy enough to handle with a bit of javascript & CSS - although I haven’t done this yet.

But the question is, how would you go about it? Is there a completely different/better way of doing it? Or should I be focusing on optimising the compareFunction?

Cheers
Baz

Hello Baz,

This is an interesting usage that can be covered by using the connectors API from instantsearch.js v2

I’ve created a jsfiddle example for you: https://jsfiddle.net/nsjhspw6/2/

I’m following almost the same logic as you, having an hardcoded of items that you want to display at first and then display the rest in an alphabetic order.

I have self-documented the code with small comments, I recommend you to read the how the customize widgets guide before going through the code I’ve shared you.

I will be happy to help you if you have any other questions or problem with the implementation I’ve shared you.

Cheers, Max :slight_smile:

1 Like

Hi Max,

Thanks for going to the trouble to demonstrate this with the fiddle.

I’m still on instantsearch v1 and don’t have any immediate plans to switch across. I’ve been reading the v2 documentation on the back of your post and am finding it a bit harder to follow than the v1 docs.

Your demo is great and does what I was asking for the most part. The only thing is that, from what I can tell, the 3 popular categories always appear, regardless of the queries or filters that have been applied. I would only want the popular categories to appear if they actually had hits within them.

This is why in my example I’ve used the facet results provided by Algolia and then compared them against the constant list of popular categories to only display the ones that came back in the results. Basically, the items in the list should be exactly the same as what would normally be provided by Algolia, only that popular ones should be displayed first.

Thinking about it has sparked some other ideas which I may give a shot. I’ll keep everyone posted if I have success.

Cheers
Baz

Ok, so this is what I’ve tried…

  1. I’ve added an attribute to the label via the widget template, so that it can be identified by designer.
  2. When onRenderHandler() is called, I search for the labels that match a designer in my popular designers list, and then shift it from lower down on the list to the top of the list with jquery. I also set a popular attribute on this label to 1.
  3. I add a bottom border to the last item in the list where popular = 1. serving as a breaker between popular designers and the rest.

Code is in this jsfiddle.

This seems to work a treat, only for one pretty big downside… To do this, I had to display all designers in my facet by default. Originally I was only displaying 15 with a Show More button to see the rest. Ideally I’d like to keep this as it was.

Any ideas?