vue-searchbox provides declarative props to query Elasticsearch, and bind UI components with different types of search queries. As the name suggests, it provides a default UI component for searchbox.

Installation

To install vue-searchbox, you can use npm or yarn to get set as follows:

Using npm

npm install @appbaseio/vue-searchbox

Using yarn

yarn add @appbaseio/vue-searchbox

Basic usage

You can watch this video for an intro to Vue Searchbox and follow along to build out the example search UI.

A simple example

The following example renders an autosuggestion search bar(search-component) with one custom component(result-component) to render the results. The result-component watches the search-component for input changes and updates its UI when the user selects a suggestion.

<template>
  <Search-base
    index="good-books-ds"
    credentials="a03a1cb71321:75b6603d-9456-4a5a-af6b-a487b309eb61"
    url="https://arc-cluster-appbase-demo-6pjy6z.searchbase.io"
    :analyticsConfig="{
      recordAnalytics: true,
      enableQueryRules: true,
      userId: 'jon@appbase.io',
      customEvents: {
        platform: 'ios',
        device: 'iphoneX'
      }
    }"
  >
  <!-- An auto-complete search box to display the suggestions and filter the
    results based on the selected value -->
  <Search-box
      id="search-component"
      :dataField="[
        {
          field: 'original_title',
          weight: 1
        },
        {
          field: 'original_title.search',
          weight: 3
        }
      ]"
      title="Search"
      defaultValue="Songwriting"
      placeholder="Search for Books"
      autosuggest
      :defaultSuggestions="[
        {
          label: 'Songwriting',
          value: 'Songwriting'
        },
        {
          label: 'Musicians',
          value: 'Musicians'
        }
      ]"
      :size="10"
      queryFormat="or"
      fuzziness="AUTO"
      showClear
      showVoiceSearch
      URLParams
      className="custom-class"
      enablePopularSuggestions
      iconPosition="left"
      :style="{ padding: 10 }"
      @valueChange="handleValue"
      @valueSelected="handleSelect"
      @queryChange="handleQueryChange"
    />
    <!-- A custom component having the `react` dependency on the
    searchbox component to display the filtered results based on the
    selected search value -->
    <search-component
      id="result-component"
      dataField="original_title"
      :react="{
        and: 'search-component'
      }"
    >
    <div
      slot-scope="{ loading, error, results }"
    >
      <div v-if="loading">Loading Results....</div>
      <div v-else-if="!!error">Something went wrong: {error.message}</div>
      <p>
        {{results.numberOfResults}} results found in {{results.time}}ms
      </p>
      <div v-bind:key="item._id" v-for="item in results.data">
        <img
          :src="item.image"
          alt="Book Cover"
        />
        <p>{{item.original_title}}</p>
      </div>
    </div>
    </search-component>
  </search-base>
</template>

<script>
import { SearchBase, SearchBox, SearchComponent } from '@appbaseio/vue-searchbox';

export default {
  name: "App",
  components: {
    SearchBase, SearchBox, SearchComponent
  },
  methods: {
    handleValue(value) {
      console.log('current value: ', value);
    },
    handleSelect(value, cause, source) {
      console.log('current value: ', value);
    },
    handleQueryChange(prevQuery, nextQuery) {
      // use the query with other js code
        console.log('prevQuery', prevQuery);
        console.log('nextQuery', nextQuery);
    },
  }
};
</script>

You can play with this example over here.

An example with a facet

<template>
  <div id="app">
    <search-base
      index="good-books-ds"
      credentials="a03a1cb71321:75b6603d-9456-4a5a-af6b-a487b309eb61"
      url="https://arc-cluster-appbase-demo-6pjy6z.searchbase.io"
      :analyticsConfig="{
        recordAnalytics: true,
        enableQueryRules: true,
        userId: 'jon@appbase.io',
        customEvents: {
          platform: 'ios',
          device: 'iphoneX'
        }
      }"
    >
      <div>
        <search-box
          id="search-component"
          :dataField="[
            {
              field: 'original_title',
              weight: 1
            },
            {
              field: 'original_title.search',
              weight: 3
            }
          ]"
          title="Search"
          placeholder="Search for Books"
          :autosuggest="true"
          :defaultSuggestions="[
            {
              label: 'Songwriting',
              value: 'Songwriting'
            },
            {
              label: 'Musicians',
              value: 'Musicians'
            }
          ]"
          :size="10"
          :debounce="100"
          queryFormat="or"
          fuzziness="AUTO"
          :showClear="true"
          :showVoiceSearch="true"
          :URLParams="true"
          :enableQuerySuggestions="true"
          iconPosition="left"
        />
        <div>
          <div>
            <search-component
              id="author-filter"
              type="term"
              dataField="authors.keyword"
              :subscribeTo="['aggregationData', 'requestStatus', 'value']"
              :URLParams="true"
              :react="{ and: ['search-component'] }"
              :value="[]"
            >
              <div
                slot-scope="{ aggregationData, loading, value, setValue }"
              >
                <div v-if="loading">Fetching Results ....</div>
                <div v-if="!loading">
                  <div
                    v-bind:key="item._key"
                    v-for="item in aggregationData.data"
                  >
                    <div key="{{item._key}}">
                      <input
                        type="checkbox"
                        :value="item._key"
                        :checked="value ? value.includes(item._key) : false"
                        @change="handleChange($event, value, setValue)"
                      />
                      <label :htmlFor="item._key">
                        {{ item._key }} ({{ item._doc_count }})
                      </label>
                    </div>
                  </div>
                </div>
              </div>
            </search-component>
          </div>
          <div>
            <search-component
              id="result-component"
              :dataField="['original_title']"
              :size="5"
              :react="{ and: ['search-component', 'author-filter'] }"
            >
              <div
                slot-scope="{ loading, error, results }"
              >
                <div v-if="loading">Fetching Results ....</div>
                <div v-if="Boolean(error)">
                  Something went wrong! Error details
                  {{ JSON.stringify(error) }}
                </div>
                <p v-if="!loading && !error">
                  {{ results.numberOfResults }} results found in
                  {{ results.time }}ms
                </p>
                <div v-if="!loading && !error">
                  <div v-bind:key="item._id" v-for="item in results.data">
                    <div key="item._id">
                      <img
                        :src="item.image"
                        alt="Book Cover"
                      />
                      <div>
                        <div >{{ item.original_title }}</div>
                        <div>
                          <div>
                              by <span>{{ item.authors }}</span>
                          </div>
                          <span>Pub {{ item.original_publication_year }}</span>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </search-component>
          </div>
        </div>
      </div>
    </search-base>
  </div>
</template>

<script>
import {
  SearchBase,
  SearchComponent,
  SearchBox
} from '@appbaseio/vue-searchbox';
import './styles.css';

export default {
  name: 'app',
  components: {
    SearchBase,
    SearchBox,
    SearchComponent
  },
  methods: {
    isChecked(value, key) {
      return value ? value.includes(key) : false;
    },
    handleChange(e, value, setValue) {
      const values = value || [];
      if (values && values.includes(e.target.value)) {
        values.splice(values.indexOf(e.target.value), 1);
      } else {
        values.push(e.target.value);
      }
      // Set filter value and trigger custom query
      setValue(values, {
        triggerDefaultQuery: false,
        triggerCustomQuery: true,
        stateChanges: true
      });
    }
  }
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
</style>

Advanced Usage

In this example, we have shown how to use vue-table to display the search results

You can check out the docs for API Reference over here.