How to build a Single Facet Refinement Toggle Component in Algolia Instant Search with VueJS
One the biggest struggle I've had while building Find A Maker was the implementation of the roles toggle button that filters the jobs thanks to Algolia Instant Search with VueJS.
The defaut Facet Refinement component allow you to build a list of checkbox based on a "facet" that you define in your index settings in Algolia.
In my case, I have a list of Job with 4 different booleans attributes like this
class Job
{
// ...
public bool $builder;
public bool $organizer;
public bool $seller;
public bool $designer;
// ...
}
So when I asked Algolia to register Facets based on those attributes, things were messy and impossible to control.
After searching and asking the Algolia team on Github, I finally re-created a VueJS component to extend their own.
The goal was to have one big button "Builder?" on the page, and when you click on it, it becomes "active" and the list of jobs is refined to show only the jobs that have the $builder === true
attribute.
And of course I wanted to customize the button so it has an image and specific html syntax.
Here's the final code
<template>
<div :class="bem()" class="is-inline-block">
<img
src="/img/icons/builder.svg"
title="I'm a builder"
alt="Builder Icon"
:class="{'is-active': isRefined}"
@click="toggleRefinement"
>
</div>
</template>
<script>
import { FACET_OR, FACET_AND, Component } from 'vue-instantsearch';
export default {
mixins: [Component],
data() {
return {
isRefined: false,
blockClassName: 'ais-refinement-list',
facetName: 'builder',
}
},
created() {
this.searchStore.addFacet(this.facetName, this.operator);
},
destroyed() {
this.searchStore.stop();
this.searchStore.removeFacet(this.facetName);
this.searchStore.start();
},
methods: {
toggleRefinement() {
this.isRefined = !this.isRefined;
return this.searchStore.toggleFacetRefinement(
this.facetName,
true
);
},
},
watch: {
operator() {
this.searchStore.addFacet(this.facetName, this.operator);
},
},
};
</script>
As you can see, this component is "hardcoded" for the $builder
attribute. You can easily extract this data and make the component more abstract thanks to VueJS props
system.
<template>
<div :class="{'is-active': isRefined}"
class="box is-inline-block is-capitalized has-text-centered"
v-tooltip="'I\'m a' + name"
@click="toggleRefinement"
>
<div class="icon">
<img
:src="icon"
:title="'I am a' + name"
:alt="name + 'Icon'"
>
</div>
<div class="">{{name}}</div>
</div>
</template>
<script>
import { FACET_OR, FACET_AND, Component } from 'vue-instantsearch';
export default {
props: ['name', 'icon'],
mixins: [Component],
data() {
return {
isRefined: false,
blockClassName: 'ais-refinement-list',
}
},
created() {
this.searchStore.addFacet(this.name, this.operator);
},
destroyed() {
this.searchStore.stop();
this.searchStore.removeFacet(this.name);
this.searchStore.start();
},
methods: {
toggleRefinement() {
this.isRefined = !this.isRefined;
return this.searchStore.toggleFacetRefinement(
this.name,
true
);
},
},
watch: {
operator() {
this.searchStore.addFacet(this.name, this.operator);
},
},
};
</script>
I consider myself as an IT Business Artisan. Or Consultant CTO. I'm a self-taught Web Developper, coach and teacher. My main work is helping and guiding digital startups.
more about meBTC
18SY81ejLGFuJ9KMWQu5zPrDGuR5rDiauM
ETH
0x519e0eaa9bc83018bb306880548b79fc0794cd08
XMR
895bSneY4eoZjsr2hN2CAALkUrMExHEV5Pbg8TJb6ejnMLN7js1gLAXQySqbSbfzjWHQpQhQpvFtojbkdZQZmM9qCFz7BXU
2024 © My Dynamic Production SRL All rights Reserved.