Updating instantSearchUI component state with Autocomplete onSelect

Right now, I am feeding in two sources: speakers and topics. I have an instantSearch component, hierarchicalMenu, representing the topic and sub-topics.

When a user searches via autocomplete and selects a topic, I’d like the results to update as if the hierarchicalMenu category was selected.

In short, how can I update the hierarchicalMenu component when selecting an option from autocomplete?

Here is a blip of some rough code,

// Section of code containing widgets
const search = instantsearch({
  searchClient,
  indexName: INSTANT_SEARCH_INDEX_NAME,
  routing: {
    stateMapping: stateMapping,
  },
  // searchFunction(helper) {
  //   if (helper.state.query === '') return;

  //   helper.search();
  // },
});

search.addWidgets([
  virtualSearchBox({}),
  configure({
    hitsPerPage: 12,
    filters: facets || '',
  }),
  stats({
    container: '#stats',
    templates: {
      text(data) {
        if (data.hasOneResult) {
          return `${data.nbHits} Speaker`;
        }

        if (data.hasNoResults) {
          return ``;
        }

        if (data.hasManyResults) {
          return `${data.nbHits} Speakers`;
        }
      },
    },
  }),
  hierarchicalMenu({
    container: document.querySelector('#topics .level-1'),
    attributes: ['topics.lvl0', 'topics.lvl1'],
    limit: 100,
    cssClasses: {
      list: ['options'],
      childList: ['level-2'],
    },
    templates: {
      item(item, { html }) {
        const isChild = item.value.includes('>');
        return `
                  <input id="${item.value}" type="checkbox" name="${item.value}" value="${
          item.value
        }" ${item.isRefined ? 'checked' : ''}>
                  <span class="topic-container ${!isChild ? 'term-parent' : 'no-children'} ${
          item.isRefined && !isChild ? 'active' : ''
        }" for="${item.value}">
                    <span class="fake-checkbox parent"></span>
                    <span class="term-name">
                      ${item.label}
                    </span>
                    ${isChild ? '' : '<span class="far fa-chevron-right arrow"></span>'}
                  </span>
        `;
      },
    },
  }),
  menu({
    container: document.querySelector('#fees .level-1'),
    attribute: 'fee_range',
    cssClasses: {
      list: ['options'],
    },
    limit: 10,
    sortBy: (a, b) => {
      let first = a.name.toLowerCase()[0];
      let last = b.name.toLowerCase()[0];

      if (first === 'u') {
        return -1;
      } else if (last === 'u') {
        return 1;
      }

      if (first === 'o') {
        if (last === 'c') {
          return -1;
        }

        return 1;
      } else if (last === 'o') {
        if (first === 'c') {
          return 1;
        }

        return -1;
      }

      return 0;
    },
    templates: {
      item(item) {
        return `
           <input id="${item.value}" type="checkbox" name="${item.value}" value="${item.value}" ${
          item.isRefined ? 'checked' : ''
        }>
          <span class="topic-container ${item.isRefined ? 'active' : ''}" for="${item.value}">
            <span class="fake-checkbox parent"></span>
            <span class="term-name">
              ${item.label}
            </span>
          </span>
        `;
      },
    },
  }),
  menu({
    container: document.querySelector('#states .level-1'),
    attribute: 'state',
    cssClasses: {
      list: ['options'],
    },
    limit: 100,
    transformItems(items) {
      return items.filter((item) => item.value);
    },
    templates: {
      item(item) {
        return `
           <input id="${item.value}" type="checkbox" name="${item.value}" value="${item.value}" ${
          item.isRefined ? 'checked' : ''
        }>
          <span class="topic-container ${item.isRefined ? 'active' : ''}" for="${item.value}">
            <span class="fake-checkbox parent"></span>
            <span class="term-name">
              ${item.label}
            </span>
          </span>
        `;
      },
    },
  }),
  menu({
    container: document.querySelector('#status .level-1'),
    attribute: 'speaker_status',
    cssClasses: {
      list: ['options'],
    },
    transformItems(items) {
      return items.filter((item) => {
        if (item.value.toLowerCase() == 'exclusive') {
          item.label = 'WSB Exclusive Speaker';
          return item;
        }
      });
    },
    templates: {
      item(item) {
        return `
           <input id="${item.value}" type="checkbox" name="${item.value}" value="${item.value}" ${
          item.isRefined ? 'checked' : ''
        }>
          <span class="topic-container ${item.isRefined ? 'active' : ''}" for="${item.value}">
            <span class="fake-checkbox parent"></span>
            <span class="term-name">
              ${item.label}
            </span>
          </span>
        `;
      },
    },
  }),
  hits({
    container: '#hits',
    cssClasses: {
      root: 'root-test',
      list: ['post-list'],
      item: ['topic__speaker'],
    },
    templates: {
      item(item) {
        const status = item.speaker_status;
        let exclusive = {
          value: false,
          title: 'Keynote Speaker',
          class: 'keynote',
        };

        if (status == 'Exclusive') {
          exclusive.value = true;
          exclusive.title = 'WSB Exclusive Speaker';
          exclusive.class = 'exclusive';
        }

        return `
              <article class="speakerCard" aria-label="${item.post_title} Card">
                <div class="speakerCard__image">
                
                    <a href="${item.permalink}" aria-label="Go to ${item.post_title}">
                      <img loading="lazy" src="${item.post_thumbnail}" alt="Profile picture of ${
          item.post_title
        }">
                    </a>
                </div>
                <div class="speakerCard__content">
                  <div class="speakerCard__details">
                    <span class="status heading--c-small-heavy ${exclusive.class}">
                      ${exclusive.title}
                    </span>
                    <a href="${item.permalink}">
                      <h2>${item.post_title}</h2>
                    </a>
                    <span class="title">
                      <p>${item.speaker_subheading}</p>
                    </span>
                  </div>
                  <div class="speakerCard__fee">
                    <span>
                      ${item.fee_range || 'Contact WSB for Fees'}
                    </span>
                  </div>
                </div>
              </article>
          `;
      },
    },
  }),
  pagination({
    container: '#pagination',
  }),
]);
// Section containing routing

export const stateMapping = {
  stateToRoute(uiState) {
    const indexUiState = uiState['speaker'] || {};

    return {
      query: indexUiState.query,
      page: indexUiState.page,
      topics:
        indexUiState.hierarchicalMenu && indexUiState.hierarchicalMenu['topics.lvl0'].join('>'),
      fee_range: indexUiState.menu && indexUiState.menu['fee_range'],
      state: indexUiState.menu && indexUiState.menu['state'],
      speaker_status: indexUiState.menu && indexUiState.menu['speaker_status'],
    };
  },
  routeToState(routeState) {
    return {
      instant_search: {
        query: routeState.query,
        page: routeState.page,
        hierarchicalMenu: {
          'topics.lvl0': routeState.topics && routeState.topics.splot('>'),
        },
        menu: {
          fee_range: routeState.fee_range,
          state: routeState.state,
          speaker_status: routeState.speaker_status,
        },
      },
    };
  },
};
// section containing the autocomplete

const categorySearchPlugin2 = {
  async getSources({ query }) {
    const results = await typesenseClient.collections('topics').documents().search({
      q: query,
      query_by: 'post_title,post_content',
      per_page: 3,
    });

    return [
      {
        sourceId: 'categorySearchPlugin',
        getItems() {
          return results.hits;
        },
        getItemInputValue({ item }) {
          return item.document.post_title;
        },
        onSelect({ item, state }) {
          console.log('Selected Topic:', item);
          console.log('Instant UI State', state);
          
          
        },
        templates: {
          header({ items, html }) {
            if (items.length === 0) {
              return null;
            }

            return html`<span class="aa-SourceHeaderTitle">Topics</span>
              <div class="aa-SourceHeaderLine" />`;
          },
          item({ item }) {
            return item.document.post_title;
          },
          noResults() {
            return 'No topics found.';
          },
        },
      },
    ];
  },
};

autocomplete({
  container: '#autocomplete',
  placeholder: 'search by speaker name or topic...',
  detachedMediaQuery: 'none',
  openOnFocus: false,
  plugins: [categorySearchPlugin2],
  initialState: {
    query: searchPageState.query || '',
  },
  async getSources({ query }) {
    const results = await typesenseClient.collections('speaker').documents().search({
      q: query,
      query_by: 'post_title,speaker_subheading,topics,post_content,state,fee_range',
      per_page: 6,
    });

    return [
      {
        sourceId: 'predictions',
        getItems() {
          return results.hits;
        },
        getItemUrl({ item }) {
          return item.document.permalink;
        },
        getItemInputValue({ item }) {
          return item.document.post_title;
        },
        onSelect({ itemUrl }) {
          return (window.location.href = itemUrl);
        },
        templates: {
          header({ items, html }) {
            if (items.length === 0) {
              return null;
            }

            return html`<span class="aa-SourceHeaderTitle">Speakers</span>
              <div class="aa-SourceHeaderLine" />`;
          },
          item({ item }) {
            return `${item.document.post_title}`;
          },
          noResults() {
            return 'No speakers found.';
          },
        },
      },
    ];
  },
  onSubmit({ state, event }) {
    setInstantSearchUiState({ query: state.query });
  },
  onReset() {
    setInstantSearchUiState({ query: '' });
  },
});

Thank you! Let me know if you need to see any more code… I’ve been stumped all day.