Plugins — InstantSearch.js

Combine the excellence of Miso's accurate search and Algolia's flexible InstantSearch.js UI framework.

With Miso's InstantSearch.js plugin, you can easily work with:

Installation

Install the npm modules:

npm install --save @miso.ai/client-sdk @miso.ai/client-sdk-algolia

In your app, import and setup the plugin:

import MisoClient from '@miso.ai/client-sdk';
import { AlgoliaPlugin } from '@miso.ai/client-sdk-algolia';

MisoClient.plugins.use(AlgoliaPlugin);

Basic Usage

This plugin provides a compatible InstantSearch.js search client interface from Miso's SDK client.

const client = new MisoClient('...');

const search = instantsearch({
  searchClient: client.algolia.searchClient(),
  indexName: '',
});

Using InstantSearch.js

With InstantSearch.js properly setup, you can connect it to Miso SDK easily:

  1. Install Miso client-side SDK for Javascript and the InstantSearch.js plugin.
  2. Substitute Algolia's search client with the one generated from Miso SDK client.

Miso's philosophy promotes a submit-based search paradigm, accomplished with an autocomplete UI pattern.

Example

//const searchClient = algoliasearch(...);
const client = new MisoClient('...');

const search = instantsearch({
  //searchClient: searchClient,
  searchClient: client.algolia.searchClient(),
  indexName: '' // empty string for default Miso engine
});

search.addWidgets([
  instantsearch.widgets.configure({
    hitsPerPage: 8
  }),
  instantsearch.widgets.searchBox({
    container: '#search-box',
    autofocus: true,
    searchAsYouType: false,
    showSubmit: true
  }),
  instantsearch.widgets.hits({
    container: '#hits',
    templates: { /* ... */ }
  })
]);

search.start();

Using Autocomplete

You can combine the power of Miso with InstantSearch.js and Autocomplete.

  1. Install the Miso client-side SDK for Javascript and the InstantSearch.js plugin.
  2. Install Autocomplete.
  3. Follow the guide to integrate InstantSearch.js and Autocomplete.
  4. Use the autocomplete client from Miso in place of Algolia's original search client (demo).

Example

Setup InstantSearch.js:

const client = new MisoClient('...');
const indexName = ''; // empty string for your default Miso engine

const search = instantsearch({
  // use Miso's search client
  searchClient: client.algolia.searchClient(),
  indexName: indexName
});

search.addWidgets([
  instantsearch.widgets.configure({
    hitsPerPage: 8
  }),
  // remove the original search box widget
  /*
  instantsearch.widgets.searchBox({
    container: '#search-box',
    autofocus: true,
    searchAsYouType: false,
    showSubmit: true,
  }),
  */
  // mount a virtual search box to manipulate InstantSearch's `query` UI state parameter
  instantsearch.connectors.connectSearchBox(() => {})({}),
  instantsearch.widgets.hits({
    container: '#hits',
    templates: { /* ... */ }
  })
]);

search.start();

Make a tool function to sync Autocomplete's query to InstantSearch.js's query state:

function setInstantSearchQueryState(query = '') {
  search.setUiState(uiState => ({
    ...uiState,
    [indexName]: {
      ...uiState[indexName],
      page: 1,
      query: query
    }
  }));
}

Setup Autocomplete:

autocomplete({
  container: '#autocomplete',
  initialState: {
    query: ''
  },
  onSubmit: ({ state }) => {
    setInstantSearchQueryState(state.query);
  },
  onReset: () => {
    setInstantSearchQueryState();
  },
  /*
  // for a submit-based search paradigm, comment out this part
  onStateChange: ({ prevState, state }) => {
    const { query: prevQuery } = prevState;
    const { query } = state;
    if (prevQuery !== query) {
      setInstantSearchQueryState(query);
    }
  },
  */
  autoFocus: true,
  getSources: ({ query }) => {
    // this is triggered on every user input
    return [{
      getItems: () => getAlgoliaResults({
        // use Miso's autocomplete client
        searchClient: client.algolia.autocompleteClient(),
        queries: [{
          query: query,
          params: {
            hitsPerPage: 5,
            attributesToHighlight: ['suggested_queries'],
          }
        }]
      }),
      onSelect: ({ setQuery, item }) => {
        const query = item._text;
        setQuery(query);
        setInstantSearchQueryState(query);
      },
      templates: {
        item: ({ item, components, html }) => html`
          <div class="aa-ItemWrapper">
            <div class="aa-ItemContent">
              <div class="aa-ItemContentBody">
                <div class="aa-ItemContentTitle">
                  ${components.Highlight({
                    hit: item,
                    attribute: 'suggested_queries',
                  })}
                </div>
              </div>
            </div>
          </div>
        `
      }
    }];
  }
});

Compatibility

The following section elaborates on the compatibility between Algolia's API and Miso's implementation.

Index Name — In InstantSearch.js and Autocomplete, you have to pass a mandatory parameter for index name to their init functions. We use this parameter to correspond to Miso's engine ID:

const client = new MisoClient('...');
const engineId = '...'; // empty string for default Miso engine

const search = instantsearch({
  //searchClient: searchClient,
  searchClient: client.algolia.searchClient(),
  indexName: engineId
});

Search Parameters

Untitled

Pagination — Both kinds of Algolia’s pagination paradigm are supported.

Untitled

For example, the following parameters:

searchClient.search([{ hitsPerPage: 10, page: 5 /* ... */ }]);

are mapped to Miso's parameters like this:

client.api.search.search({ rows: 10, start: 10 * 5 /* ... */ });

Filters — Algolia's filter expressions are translated to Miso's syntax.

Untitled

Facets

Untitled

Highlighting

Untitled

Customization

Custom search handler — You can fully control how InstantSearch.js's search request is processed by passing a handler function:

const client = new MisoClient('...');
const searchClient = client.algolia.searchClient({
  handleSearch: async ({ misoApiName, mapRequest, callMisoApi, mapResponse }, request, options) => {
    // this is equivalent to the default behavior
    const payload = mapRequest(misoApiName, request);
    const misoResponse = await callMisoApi(misoApiName, payload, options);
    return mapResponse(misoApiName, request, misoResponse);
  }
});
Icon/Activity Icon/Add Icon/API Icon/Arrow/Down Icon/Arrow/Left Icon/Arrow/Right Icon/Arrow/TopRight Icon/Arrow/Up Icon/Bento Icon/Billing Icon/Bin Icon/Book Icon/Bookmark/Default Icon/Bookmark/Filled Icon/Calendar Icon/Caret/Down Icon/Caret/Up Icon/Chavron/DownIcon/Chavron/LeftIcon/Chavron/RightIcon/Chavron/UpIcon/Checknox/CheckedIcon/Checknox/Unchecked Icon/Checklist Icon/Chip Icon/Clipboard / Copied Icon/Clipboard/Default Icon/Clock/Stopwatch Icon/CMD Icon/Data/Catalog Icon/Data/Engine Icon/Data/Group Icon/Data/Interact Icon/Data/Users Icon/Dive Icon/Docs/Key Icon/Dojo Icon/Email Icon/Env/Development Icon/Env/Playground Icon/Env/Prod Icon/Folder Icon/Fullscreen/Collapse Icon/Fullscreen/Expand Icon/Guides/Multiple Icon/Guides/Single Icon/Hashtag Icon/Heart/Outline Icon/Heart/Solid Icon / Cart z Icon / Click Icon / Clock Icon / Data Icon / Doc Icon / EmptyCart z Icon/Social/Facebook Icon / Genome Incognito Icon / Money Icon/Social/ProductHunt Icon / Search Icon/Social/Twitter Icon / User Icon/Info/Error Icon/Info/Info Icon/Info/Question Icon/Info/Warning Icon/Interact/Download Icon/Interact/Edit Icon/Interact/External v2 Icon/Interact/External Icon/Interact/Filter Icon/Interact/Logout Icon/Interact/Options Icon/Interact/Re-order Icon/Interact/Reload Icon/Interact/Remove Icon/Interact/Replace Icon/Interact/Search Icon/Interact/Shuffle Icon/Interact/Undo Icon/Interact/Upload Icon/Interact/Video Icon/Invoice Icon/Loading Icon/Loading Icon/Lock/Locked Icon/Lock/Unlocked Icon/Lock Icon/Mapping Menu Icon/Notification Icon/Overview Icon/Person/Team Icon/Person/User Icon/Plan/Enterprise Icon/Plan/Growth Icon/Plan/Startup Icon/Plan/Trial Icon/Recipe Icon/Rocket Icon/Settings/App Icon/Settings/User Icon/Settings Icon/Shrine Icon/Sidebar/Close Icon/Sidebar/Open Icon/Slideout Icon/Sort/Ascending Icon/Sort/Default Icon/Sort/Descending Icon/Star/Filled Icon/Star/Outlined Stopwatch Icon/Support Icon/Tag Icon/Interact/Thumb/Dislike Icon/Interact/Thumb/Like Icon/Tick Icon/Trend/New Icon/Trend/Trending Icon/Tutorial Icon/Lock/Unlocked Icon/View/Grid Icon/View/List Icon/Watchlist/Add