Menambahkan Algolia Search di Nuxt JS

August 12, 2021 4 min read
Belajar bagaimana menambahkan Algolia Search di Nuxt JS.

Search Box atau kotak pencarian menjadi salah satu fitur penting pada sebuah situs web. Jika kita menggunakan Wordpreess atau CMS sejenis akan lebih mudah karena biasanya sudah ada saat proses installasi.

Lalu bagaimana jika kita menggunakan Nuxt JS? Disinilah Algolia sangat berperan penting untuk membantu para pengguna Nuxt JS menambahkan search box ke situs/aplikasi kita.

Berikut ini cara menambahkan Algolia Search di NuxtJS.

Install paket yang dibutuhkan

Pertama install semua paket yang di butuhkan, setidaknya ada 5 paket yang diperlukan.

npm install vue-instantsearch algoliasearch nuxt-content-algolia remove-markdown v-click-outside --save


Buat custom file plugin vue-instantsearch.js

Selanjutnya buat sebuah file dengan nama vue-instantsearch.js di dalam folder plugins, kemudian isi dengan baris kode berikut.

import Vue from 'vue'
import InstantSearch from 'vue-instantsearch'

Vue.use(InstantSearch)


Daftarkan plugin ke nuxt.config.js

Selanjutnya jangan lupa daftarkan plugin custom yang sudah dibuat ke dalam nuxt.config.js.

export default {
  // ...
  plugins: [
    '~/plugins/vue-instantsearch'
  ],
  // ...
}


Set Transpile di nuxt.config.js

Tambahkan transpile build di nuxt.config.js

export default {
  build: {
    transpile: ['vue-instantsearch', 'instantsearch.js/id']
  },
}

Konfigurasi nuxt-content-algolia

Selanjutnya konfigurasi modul nuxt-content-algolia di nuxt.config.js

export default {
  // ...
  buildModules: [
    'nuxt-content-algolia'
  ],
  nuxtContentAlgolia: {
    appId: process.env.ALGOLIA_APP_ID,
    apiKey: process.env.ALGOLIA_API_KEY,
    paths: [
      {
        name: 'articles',
        index: 'articles',
        fields: ['title', 'description', 'bodyPlainText']
      }
    ]
  },
}

Buat file .env

Selanjutnya buat file .env untuk menyimpan app id dan api key Algolia.

ALGOLIA_APP_ID=algolia_app_id_mu
ALGOLIA_API_KEY=algolia_app_key_mu

Buat custom hook untuk menghapus html dari konten body

Tag HTML dan atribut lainnya tidak diperlukan saat pencarian. Jadi, kita membuat teks isi biasa menggunakan paket remove-markdown.

export default {
  // ...
  hooks: {
    'content:file:beforeInsert': (content) => {
      const removeMd = require('remove-markdown');
      if (content.extension == 'md') {
        content.bodyPlainText = removeMd(content.text);
      }
    }
  }
}

Buat file Search.vue di folder components

Selanjutnya buat komponen bernama Search.vue

<template>
  <ais-instant-search
    :search-client="searchClient"
    index-name="articles"
  >
    <ais-configure :attributesToSnippet="['bodyPlainText']" :hits-per-page.camel="5" />
    <ais-autocomplete v-click-outside="onClickOutside">
      <div slot-scope="{ currentRefinement, indices, refine }" class="md:relative">
        <div class="relative">
          <font-awesome-icon :icon="['fas', 'search']" class="absolute h-4 text-gray-400 mt-3 ml-3" />
          <input
            type="search"
            ref="searchInput"
            class="w-full py-2 px-4 pl-10 bg-gray-100 rounded"
            :value="currentRefinement"
            @input="refine($event.currentTarget.value)"
            placeholder="Search - Ctrl+K to focus"
            autocomplete="off"
            @focus="showResults = true"
            @keydown.up.prevent="highlightPrevious(indices[0].hits.length)"
            @keydown.down.prevent="highlightNext(indices[0].hits.length)"
            @keydown.enter="goToArticle(indices)"
          >
        </div>
        <div v-if="currentRefinement.length && showResults" class="absolute right-0 z-10 transform mt-3 px-2 w-screen max-w-md sm:px-0">
          <div class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden">
            <div class="relative grid gap-6 bg-white text-gray-700 px-4 py-4 sm:gap-8 sm:p-4">
              <div v-if="currentRefinement" v-for="section in indices" :key="section.objectID" class="divide-y divide-gray-300">
                <div v-if="section.hits.length">
                  <h2 class="uppercase text-gray-700 py-1 px-2">{{ section.indexName }}</h2>
                </div>
                <NuxtLink to="#" v-for="(hit, index) in section.hits" :key="hit.objectID"
                  class="block text-sm col-span-2 py-2 transition ease-in-out duration-150"
                  :class="{ 'bg-gray-100': isCurrentIndex(index) }">
                  <div class="px-2" @mouseover="highlightedIndex = index">
                    <ais-highlight attribute="title" :hit="hit" class="block text-gray-600 font-semibold tracking-wide" />
                    <ais-snippet attribute="bodyPlainText" :hit="hit" class="block text-gray-400 font-base" />
                  </div>
                </NuxtLink>
              </div>
              <ais-powered-by theme="light" class="px-2" />
            </div>
          </div>
        </div>
      </div>
    </ais-autocomplete>
  </ais-instant-search>
</template>

<script>
import algoliasearch from 'algoliasearch/lite'
import vClickOutside from 'v-click-outside'

export default {
  directives: {
    clickOutside: vClickOutside.directive
  },
  data() {
    return {
      searchClient: algoliasearch ('6C3W4JP2I6', 'ea72adbc6e9f7b4da0b111f7319cd3a3'),
      showResults: false,
      highlightedIndex: -1 
    }
  },
  mounted() {
    this.$nextTick(function () {
      window.addEventListener('keydown', event => {
        if((event.metaKey || event.ctrlKey) && event.key === 'k') {
          this.$refs.searchInput.focus()
          event.preventDefault()
        }
      })
    })
  },
  watch: {
    '$route' () {
      this.showResults = false
      this.$refs.searchInput.blur()
    }
  },
  methods: {
    onClickOutside() {
      this.showResults = false
    },
    highlightPrevious(resultsCount) {
      if (this.highlightedIndex > 0) {
        this.highlightedIndex -= 1
      } else {
        this.highlightedIndex = resultsCount - 1
      }
    },
    highlightNext(resultsCount) {
      if (this.highlightedIndex < resultsCount - 1) {
        this.highlightedIndex += 1
      } else {
        this.highlightedIndex = 0
      }
    },
    isCurrentIndex(index) {
      return index === this.highlightedIndex
    },
    goToArticle(indices) {
      this.$nuxt.$router.push('/articles/' + indices[0].hits[this.highlightedIndex].objectID)
    }
  }
}
</script>


Tambahkan Komponen Search ke Dalam Layout

Terakhir tambahkan <Search/> ke dalam halaman yang kamu inginkan.

<template>
  <div>
    <Search />
  </div>
</template>


Itulah cara menambahkan Algolia search ke aplikasi/website berbasis Nuxt.js, semoga bermanfaat.


Terima kasih sudah membaca artikel "Menambahkan Algolia Search di Nuxt JS"
Bagikan
Silahkan Login untuk berkomentar.