How to build a Single Facet Refinement Toggle Component in Algolia Instant Search with VueJS

profile picture

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.

Context

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.

Building the solution

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>

Improvements

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>
vuejs
algolia
search
instant search

about me

profile picture

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 me

follow me

newsletter

A weekly email with the latests articles

support my work

Start trading on binance
  • BTC

    BTC

    18SY81ejLGFuJ9KMWQu5zPrDGuR5rDiauM

  • ETH

    ETH

    0x519e0eaa9bc83018bb306880548b79fc0794cd08

  • Monero

    XMR

    895bSneY4eoZjsr2hN2CAALkUrMExHEV5Pbg8TJb6ejnMLN7js1gLAXQySqbSbfzjWHQpQhQpvFtojbkdZQZmM9qCFz7BXU

2024 © My Dynamic Production SRL All rights Reserved.