Building an Interactive Showcase with Vue.js & Vue InstantSearch

A presentation at Vue.js Paris in January 2019 in Paris, France by Sarah Dayan

Slide 1

Slide 1

Hi, I’m Sarah x x

Slide 2

Slide 2

Slide 3

Slide 3

Slide 4

Slide 4

Slide 5

Slide 5

Slide 6

Slide 6

Slide 7

Slide 7

Slide 8

Slide 8

Slide 9

Slide 9

InstantSearch AutoComplete GeoSearch Full search interface Autocomplete menu Search through locations

Slide 10

Slide 10

InstantSearch AutoComplete GeoSearch Full search interface Autocomplete menu Search through locations Dynamic Scoped components slots Mixins

Slide 11

Slide 11

Slide 12

Slide 12

InstantSearch AutoComplete GeoSearch Full search interface Autocomplete menu Search through locations

Slide 13

Slide 13

Hierarchical menu Refinement list

Slide 14

Slide 14

Widget Switcher

Slide 15

Slide 15

Slide 16

Slide 16

Slide 17

Slide 17

<widget-switcher :widgets=”[ { title: ‘refinementList’, body: RefinementList }, { title: ‘menu’, body: Menu }, { title: ‘hierarchicalMenu’, body: HierarchicalMenu } ]” />

Slide 18

Slide 18

Registered component import RefinementList from ‘@/components/widgets/RefinementList’ export default { components: { RefinementList } } <refinement-list>

Slide 19

Slide 19

Component exposed as a JavaScript object import RefinementList from ‘@/components/widgets/RefinementList’ export default { data() { return { RefinementList } } } RefinementList

Slide 20

Slide 20

Dynamic components ⚡

Slide 21

Slide 21

Slide 22

Slide 22

Switching strategy <template> <div> <component :key=”index” :class=”{ ‘hidden’: currentWidgetIndex !== index }” v-for=”(widget, index) in widgets” :is=”widget.body” /> </div> </template>

Slide 23

Slide 23

<ais-refinement-list> <ais-menu> Conjunctive Disjunctive

Slide 24

Slide 24

Alternative switching strategy <component :is=”widgets[currentWidgetIndex].body” />

Slide 25

Slide 25

AutoComplete

Slide 26

Slide 26

Slots Parent component <template> <div> <child-component> <p>Data for the child.</p> </child-component> </div> </template> Child component <template> <div> <p> <slot><!— Goes here! —></slot> </p> </div> </template>

Slide 27

Slide 27

Scoped slots = slots + Parent component <template> <div> <child-component :todos=”todos”> <template slot-scope=”{ todo }”> <span v-if=”todo.done”> ✅ </span> {{ todo.text }} </template> </child-component> </div> </template> Child component <template> <ul> <li :key=”todo.id” v-for=”todo in todos” > <slot :todo=”todo”> {{ todo.text }} </slot> </li> </ul> </template>

Slide 28

Slide 28

<ais-autocomplete> Vue InstantSearch autocomplete widget <template slot-scope=”{ indices, refine }”> Data from the widget <vue-autosuggest :suggestions=”indicesToSuggestions(indices)” @selected=”onSelect” :input-props=”{ onInputChange: refine }” > <template slot=”header”> Press enter to select, ↑↓ to navigate, esc to dismiss </template> <template slot-scope=”{ suggestion }”> <img :src=”suggestion.item.image”> <h5> <ais-highlight :hit=”suggestion.item” attribute=”name” /> </h5> <p>$ {{ suggestion.item.price }}</p> <span v-if=”suggestion.item.free_shipping”> Free Shipping </span> </template> </vue-autosuggest> </template> </ais-autocomplete> Custom template using data from the widget

Slide 29

Slide 29

GeoSearch

Slide 30

Slide 30

Connectors

Slide 31

Slide 31

Connector + Vue InstantSearch = mixin import { connectGeoSearch } from ‘instantsearch.js/es/connectors’ import { createWidgetMixin } from ‘vue-instantsearch’ export default { mixins: [ createWidgetMixin({ connector: connectGeoSearch }) ] }

Slide 32

Slide 32

Slide 33

Slide 33

<template <google-map> <google-map-marker :key=”index” v-for=”(marker, index) in markers” :position=”marker.position” /> <google-map-infowindow :key=”index” v-for=”(marker, index) in markers” :position=”marker.position” /> </google-map> </template> <script> import { connectGeoSearch } from ‘instantsearch.js/es/connectors’ import { createWidgetMixin } from ‘vue-instantsearch’ import { Map, Marker, InfoWindow } from ‘vue2-google-maps’ export default { mixins: [createWidgetMixin({ connector: connectGeoSearch })], computed: { markers() { return Boolean(this.state) ? [] : this.state.items.map(({ /* … / }) => ({ // })) } }, / … */ } </script>

Slide 34

Slide 34

= algolia.com/doc/guides/building-search-ui/widgets/showcase/vue/

Slide 35

Slide 35

Thank you! @frontstuff_io