christostsang
christostsang

Reputation: 1841

Algolia & Vue InstantSearch: Customising widgets with slot

I am trying to modify the output of an InstantSearch widget for Vue.

In the documentation (https://www.algolia.com/doc/api-reference/widgets/hits/vue/#customize-the-ui) it says that using the scope-slot it will override the complete DOM output of the widget:

enter image description here

But it does not seem to be the case here. This is my code below using slot with a simple <tr> and <td> elements:

enter image description here

Instead of rendering a <tr> with <td> inside of it, I see here:

enter image description here

The output is this:

enter image description here

If I go to inspect element and I delete the elements I mentioned above (see how div, ol and li are deleted):

enter image description here

Then the result is correct:

enter image description here

Am I doing something wrong? Shouldn't slot override the DOM output and leave the rest to the developer to style?

Any help would be much appreciated!

Upvotes: 2

Views: 1854

Answers (2)

christostsang
christostsang

Reputation: 1841

Although @Samuel Vaillant pointed me at the correct path, I believe the code below can help others with the same issue as me (populating HTML tables with Algolia results) without needing to create custom widgets:

<template>
  <ais-hits>
    <table slot-scope="{ items }">
      <thead>
        <tr>
          <th>Name</th>
          <th>Description</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in items" :key="item.objectID">
          <td>
            <ais-highlight :hit="item" attribute="name" />
          </td>
          <td>
            <ais-highlight :hit="item" attribute="description" />
          </td>
        </tr>
      </tbody>
    </table>
  </ais-hits>
</template>

Upvotes: 2

Samuel Vaillant
Samuel Vaillant

Reputation: 3847

You have to use the default slots rather than item. You'll have full control over the render.

<ais-hits>
  <ol slot-scope="{ items }">
    <li v-for="item in items" :key="item.objectID">
      <ais-highlight :hit="item" attribute="name" />
      <p>
        <ais-highlight :hit="item" attribute="description" />
      </p>
    </li>
  </ol>
</ais-hits>

Here is an example on CodeSandbox.


The ais-Hits will always wrap the default slot with a div (see GitHub for the explaination). The only alternative to avoid this issue is to create your own widget with the mixin createWidgetMixin:

<template>
  <ol v-if="state">
    <li v-for="item in state.hits" :key="item.objectID">
      <ais-highlight :hit="item" attribute="name" />
      <p>
        <ais-highlight :hit="item" attribute="description" />
      </p>
    </li>
  </ol>
</template>

<script>
import { createWidgetMixin } from "vue-instantsearch";
import { connectHits } from "instantsearch.js/es/connectors";

export default {
  mixins: [createWidgetMixin({ connector: connectHits })]
};
</script>

Here is an example on CodeSandbox.

Upvotes: 4

Related Questions