Supafolio JavaScript SDK
This JavaScript SDK is available for users looking to quickly and easily build predictive autocomplete search fields, product carousels, search results and full details pages through the use of easily configurable widgets.
Table of Contents
- Installation
- Features
- Usage
- Documentation
- Cheatsheet
- FAQ
- License
Installation
The JavaScript SDK works on the frontend, it is UMD compatible and can be used it with any module loader. When not using any module loader, it will export a supafolio
function in the window object.
jsDelivr
<link href="https://cdn.jsdelivr.net/npm/supafolio-sdk@0/dist/supafolio.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/supafolio-sdk@0/dist/supafolio.min.js" type="text/javascript"></script>
npm
$ npm install --save supafolio-sdk
You need to manually load the companion CSS file into your page.
Alternatively you can import the css in your JavaScript if you're using a module loader
import "node_modules/supafolio-sdk/dist/supafolio.min.css";
Features
- Predictive autocomplete widget
- Displays suggestions to end-users as they type
- Shows top suggestion as a hint (i.e. background text)
- Supports custom templates to allow for UI flexibility
- Triggers custom events
- Item lookup widget
- Displays a list, grid or carousel of results to end-users
- Number of results per row configurable
- Features of the carousel can be customised (i.e. navigational dots)
- Carousel triggers custom events
- Full details widget
- Allows end-users to create custom templates to display item data
- Filter used to fetch data is configurable
- Search results widget
- Completely customise a search results using sub widgets
- Search parameters management
- Multiple types of filters to choose from
- Pagination and / or Load More widgets
- Supports custom created sub widgets
Usage
To initialise the Supafolio JavaScript SDK, you need a Supafolio account and the accompanying Application ID
, API Key
and Catalog ID
.
Once you have this, in 30 seconds this basic usage example will show you how to add a simple widget to display a lookup carousel.
Initialise the client
You first need to initialise the client. For that you need your Application ID
, API Key
and Catalog ID
. For demo purposes only you can use the example Application ID
, API Key
and Catalog ID
shown below.
If you want to apply static data from S3 and don't do any Algolia requests, you can pass a staticData
boolean in the opts object e.g
opts = {
staticData: true
}
// const supafolio = require( "supafolio-sdk" );
// import supafolio from "supafolio-sdk";
// or just use supafolio if you are using a <script> tag
const client = supafolio( "LZ2Q6SA8YD", "2ed4b5c343fb7251f8a86c87ae3e8b76", "demo", opts );
Use the addLookupWidget
method to render a carousel of products in the Fiction
collection.
NOTE: The container
option is required with all widgets, it defines where on the page the widget should be rendered. The container
option accepts a standard CSS selector or DOM element. It is referenced using document.querySelector
which means, if a class name selector is used, the first one found will be the container.
client.addLookupWidget({
container: "#products-lookup-wrapper",
source: "products",
collection: "Fiction",
perRow: 5,
templates: {
item: `<img src="{{ item.image }}" alt="{{ item.title }}" />`
}
});
Documentation
Predictive autocomplete widget
Adds a fast and fully-featured auto-completion menu to your search box displaying results "as you type".
Setup
There are 2 required options needed to add a predictive autocomplete widget container
and sources
. See below for option definitions.
client.addPredictiveWidget({
container: "#predictive-wrapper",
sources: ["products"],
});
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
sources
- Required (Array) - This defines which index the predictive search will get your suggestions from.- Array can contain a simple string of the index. i.e.
products
,contributors
orsupplementals
. - Array can contain an object for the index source to allow other options to be set.
-
name
- Required (String) - The name of the index to query. -
displayKey
- (String) - The field to use when a suggestion is selected. -
header
- (String) - The label to use for the section header -
suggestion
: - (String) - The template to use for the suggestion, -
hitsPerPage
: - (Number) - The maximum number of results to return for a section.
-
- Array can contain a simple string of the index. i.e.
-
highlightResult
- (Boolean) - Defines whether the returned values should have the matches highlighted. Defaults totrue
. -
placeholder
- (String) - The placeholder text to add to the search box -
inputID
- (String) - Required if the input template is changed to identify the ID of the search input field to attach the autocomplete to. -
templates
- (Object) - Allows the default templates to be changed-
input
- (String) - The template used to render the search box
-
-
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the wrapping DOMElement. Defaults tosupafolio-predictive-search-box
. -
input
- (String) - The class used for the search input field. Defaults tosupafolio-predictive-search-box__input
.
-
-
options
- (Object) - Options used to control the behaviour of the autocomplete-
autoselect
- (Boolean) - If true, the first rendered suggestion in the dropdown will automatically selected. -
autoselectOnBlur
- (Boolean) – If true, when the input is blurred, the first rendered suggestion in the dropdown will automatically selected. -
hint
– (Boolean) – If false, the autocomplete will not show a hint. Defaults totrue
. -
debug
– (Boolean) – If true, the autocomplete will not close on blur. Defaults tofalse
. -
openOnFocus
- (Boolean) – If true, the dropdown menu will open when the input is focused. Defaults tofalse
. -
appendTo
– (String) – If set with a DOM selector, doesn't wrap the input and appends the wrapper and dropdown menu to the first DOM element matching the selector. It automatically positions the wrapper under the input, and sets it to the same width as the input. Can't be used with hint: true, because hint requires the wrapper around the input. -
dropdownMenuContainer
– (String) – If set with a DOM selector, it overrides the container of the dropdown menu. -
cssClasses
- (Object) - Allows the default css classes to be changed.-
root
– (String) – the root classes. Defaults tosupafolio-autocomplete
. -
prefix
– (String) – the CSS class prefix of all nested elements. Defaults tosupafolio
. -
noPrefix
- (Boolean) – set this to true if you wish to not use any prefix. Without this option, all nested elements classes will have a leading dash. Defaults tofalse
. -
dropdownMenu
– (String) – the dropdown menu CSS class. Defaults todropdown-menu
. -
input
– (String) – the input CSS class. Defaults toinput
. -
hint
– (String) – the hint CSS class. Defaults tohint
. -
suggestions
– (String) – the suggestions list CSS class. Defaults tosuggestions
. -
suggestion
– (String) – the suggestion wrapper CSS class. Defaults tosuggestion
. -
cursor
– (String) – the cursor CSS class. Defaults tocursor
. -
dataset
– (String) – the dataset CSS class. Defaults todataset
. -
empty
– (String) – the empty CSS class. Defaults toempty
.
-
-
minLength
– The minimum character length needed before suggestions start getting rendered. Defaults to1
. -
autoWidth
– This option allow you to control the width of autocomplete wrapper. Whenfalse
the autocomplete wrapper will not have the width style attribute and you are be able to put your specific width property in your css to control the wrapper. Default value istrue
.
-
Events
The autocomplete component triggers the following custom events. These functions are added to the options object passed to addPredictiveWidget
.
-
opened
- (Function) - Triggered when the dropdown menu of the autocomplete is opened. -
shown
- (Function) - Triggered when the dropdown menu of the autocomplete is shown (opened and non-empty). -
empty
- (Function) - Triggered when all datasets are empty. -
closed
- (Function) - Triggered when the dropdown menu of the autocomplete is closed. -
updated
- (Function) - Triggered when a dataset is rendered. -
selected
- (Function) - Triggered when a suggestion from the dropdown menu is selected. The event handler will be invoked with 3 arguments: the event object, the suggestion object, and the name of the dataset the suggestion belongs to.
Item lookup widget
The lookup widget allows you to create either a list, grid or carousel of results based on a list of IDs, a named collection or a custom query filter.
Setup
There are 4 required options needed to add a item lookup autocomplete widget container
, source
, templates.item
and either collection
, objectIDs
or filter
. See below for option definitions.
client.addLookupWidget({
container: "#products-lookup-wrapper",
collection: "Fiction",
source: "products",
templates: {
item: `<img src="{{ item.image }}" alt="{{ item.title }}" />`
}
});
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
source
- Required (String) - This defines which index the lookup search will get your results from. i.e.products
,contributors
orsupplementals
. -
filter
- (String) - Used to set a query to fetch items. See examples below. -
collection
- (String) - Will return items which are in the defined collection. -
objectIDs
- (Array) - Accepts an array of IDs. Results matching those IDs are returned. -
static
- (Boolean) - Set totrue
to avoid requesting product data from Algolia. -
ranking
- (String) - States how the results should be ordered. Available static values arerelevance:desc
,relevance:asc
,asEntered:desc
,asEntered:asc
. Other sort by options are based on replicas that have been set up for your data. i.e. if your data it set up to sort by publication date you could pass the publication date data attribute aspublicationDate:desc
orpublicationDate:asc
. -
hitsPerPage
- (Number) - Sets how many items to be returned. Maximum is 100. Defaults to100
. -
perRow
- (Number) - Sets how many items to render on each row of the layout grid. Defaults to5
. -
distinct
- (Boolean) - Allows items in the same data grouping to not all be returned. Defaults tofalse
. -
itemAlign
- (String) - Define how to align content in the grid. Available values areleft
,center
orright
. Defaults tocenter
. -
carousel
- (Object | Boolean) - Set tofalse
to disable the carousel and instead render a grid or list. Set anObject
of options to customise the behaviour of the carousel. The carousel is built using Flickity for a list of available options see the documentation. The Flickity object will be return if carousel is enabled, see example below. -
resultHandler
- (Function) - Method to change the item data passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
item
- (String) - The template used each result item. If not defined then a JSON string of the item will be output.
-
-
classes
- (Object) - Allows the default css classes to be changed-
columns
- (String) - The class used for each of the grid columns generated. Defaults tosupafolio-grid-columns
.
-
Option examples
filter
Get products with the imprint Pan
or Picador
.
client.addLookupWidget({
filter: "imprint:Pan OR imprint:Picador"
});
Get products with the imprint Pan
or Picador
and is an eBook
format.
client.addLookupWidget({
filter: "(imprint:Pan OR imprint:Picador) AND format:eBook"
});
Get products with the imprint Pan
or Picador
that is an eBook
format and less than £10
.
client.addLookupWidget({
filter: "(imprint:Pan OR imprint:Picador) AND format:eBook AND prices.GBP < 10"
});
resultHandler
Add an SEO friendly version of the title to the item.
client.addLookupWidget({
resultHandler( item ) {
item.seoTitle = client.helpers.seoURL( item.title );
return item;
}
});
carousel
Trigger the Flickity resize method to resize the carousel and re-position cells.
client.addLookupWidget( options ).then( carousel => {
carousel.resize();
});
Full details widget
Queries the API for a specific record to create a page which renders all the data for that record.
Setup
There are 4 required options needed to add a full details widget container
, source
, objectID
and templates.item
. See below for option definitions.
client.addDetailsWidget({
container: "#products-details-wrapper",
objectID: "9781447294627",
source: "products",
templates: {
item: `<div>
<img src="{{ item.image }}" alt="{{ item.title }}" />
<h1>{{item.title}}</h1>
<h2>{{item.subtitle}}</h2>
<h3>{{item.contributorByLine}}</h3>
<div >{{{item.description}}}</div>
</div>`
}
});
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
source
- Required (String) - This defines which index the item will be returned from. i.e.products
,contributors
orsupplementals
. -
objectID
- Required (String) - A single result matching this ID will be returned. -
getContributorSupplementals
- Required (Boolean) - If true, a second query will be made on calls for products to get all the supplementals for matching contributors. Defaults tofalse
. -
resultHandler
- (Function) - Method to change the item data passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
item
- (String) - The template used the result item. If not defined then a JSON string of the item will be output.
-
-
classes
- (Object) - Allows the default css classes to be changed-
columns
- (String) - The class used for each of the grid columns generated. Defaults tosupafolio-grid-columns
.
-
-
static
- (Object) - (Optional) Determines if indexes should not be queried from Algolia-
products
- (Boolean) - Set totrue
to avoid requesting product data from Algolia -
contributors
- (Boolean) - Set totrue
to avoid requesting contributor data from Algolia
-
NOTE: The product/contributor link information is part of the contributor record and can be accessed on the method from inside resultHandler
method.
Search results widget
The search results widget is set up slightly differently to the other widgets. A search results page is made up of individual components, also known as widgets. Widgets are UI components for either the search input (search bar, facets/filters, etc.) or the search output (actual results). See below of a
Each widget is independent, and their rendering is bound to the search. They have the following lifecycle:
-
Configuration
- each widget can add new query parameters. -
Initial rendering
- before the initial search, the widget may update the UI. -
Rendering
- on each search, after the results come back, the widgets update themselves.
Setup
Initialisation
There is only 1 required option needed to add a search details widget source
. See below for option definitions.
const search = client.search({
source: "products"
});
Options
-
source
- Required (String) - This defines which index the lookup search will get your results from. i.e.products
,contributors
orsupplementals
. -
searchFunction
- (Function) - A hook that will be called each time a search needs to be done, with the helper as a parameter. It’s your responsibility to call helper.search(). This option allows you to avoid doing searches at page load for example. -
searchParameters
- (Object) - Additional parameters to pass to the Search API. For a list of available options see the documentation -
urlSync
- (Object | Boolean) - Allows the current search to be synchronised with the browser url. Defaults totrue
. Set tofalse
to disable url synchronisation. Set anObject
of options to customise the behaviour of the url synchronisation.-
mapping
- (Object) - Object used to define replacement query parameter to use in place of another. Keys are current query parameters and value the new value, e.g.{ q: 'query' }
. -
threshold
- (Number) - Idle time in ms after which a new state is created in the browser history. Defaults to700
. The url is always updated at each keystroke but we only create a "previous search state" (activated when click on back button) every 700ms of idle time. -
tracked
- (Array) - Accepts an array of strings. Parameters that will be synchronised in the URL. Defaults to["query", "attribute:*", "index", "page", "hitsPerPage"]
.attribute:*
means all the faceting attributes will be tracked. You can track only some of them by usingattribute:imprint
,attribute:categories
.
-
NOTE: URL synchronisation provides two benefits:
- Working back/next browser buttons
- Copy and share the current search url
NOTE: By default the URL parameter of the result page is p
. This is a reserved query parameter in WordPress. If you have urlSync enabled you will need to provide a mapping of p to a new custom query parameter. i.e. mapping: { p: "supafolio_page" }
.
Add widgets
To build your search results page, you need to combine several widgets. Start by adding a searchBox
widget, a results
widget, and a pagination
widget to build a basic results page.
search.addWidget(
search.widgets.searchBox({
container: "#search-box-wrapper"
})
);
Note: The Supafolio JavaScript SDK comes with built-in widgets, but you can also build your own custom widgets:
search.addWidget({
getSearchParameters() {},
init() {},
render() {}
});
You can also add multiple at the same time.
search.addWidget(
search.widgets.searchBox({
container: "#search-box-wrapper"
}),
search.widgets.stats({
container: "#stats-wrapper"
})
);
Start
Once all the widgets have been added to the search instance, start the rendering by calling the start() method.
search.start();
Search Widgets
Search Box Widget
The search box widget is where you users type their search queries.
search.addWidget(
search.widgets.searchBox({
container: "#search-box-wrapper"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
placeholder
- (String) - The placeholder text to add to the search box -
wrapInput
- (Boolean) - Wrap the input in a div. Defaults totrue
. -
clearRefinementsOnSearch
- (Boolean) - If true all refinements will be remove when a new query is typed. Defaults totrue
. -
inputID
- (String) - Required if the input template is changed to identify the ID of the search input field. -
templates
- (Object) - Allows the default templates to be changed-
searchBox
- (String) - The template used to render the search box
-
-
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the wrapping DOMElement. Defaults tosupafolio-search-box
. -
input
- (String) - The class used for the search input field. Defaults tosupafolio-search-box__input
.
-
Results Widget
The results widget is the main component that displays results from Supafolio.
search.addWidget(
search.widgets.results({
container: "#results-wrapper"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
perRow
- (Number) - Sets how many items to render on each row of the layout grid. -
itemAlign
- (String) - Define how to align content in the grid. Available values areleft
,center
orright
. Defaults tocenter
. -
loadMore
- Required (String | DOMElement) - CSS selector or DOM element defining where the linked load more button is located. This is used when using a load more widget instead of the pagination widget for page navigation. -
resultHandler
- (Function) - Method to change the item data passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
empty
- (String) - The template used when there are item found -
item
- (String) - The template used to render the result item
-
-
classes
- (Object) - Allows the default css classes to be changed-
columns
- (String) - The class used for each of the grid columns generated. Defaults tosupafolio-grid-columns
.
-
Sort By Selector Widget
The sort by selector widget lets you reorder your results. You need multiple indices for this to work.
search.addWidget(
search.widgets.sortBySelector({
container: "#sort-by-wrapper"
options: [
{ value: "prices_gbp_desc", label: "Highest price" },
{ value: "prices_gbp_asc", label: "Lowest price" }
]
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
options
- Required (Array) - This defines which the options to add to the dropdown. Expects objects defining a value and label.-
value
Required (String) - The name of the index to target -
label
Required (String) - The label displayed in the dropdown
-
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
selectID
- (String) - Required if the select template is changed to identify the ID of the select field. -
templates
- (Object) - Allows the default templates to be changed-
sortBySelector
- (String) - The template used render the select
-
Per Page Selector Widget
The per page selector widget lets you select the number of results you want displayed at once.
search.addWidget(
search.widgets.perPageSelector({
container: "#per-page-wrapper"
options: [
{ value: 1, label: "1 per page" },
{ value: 10, label: "10 per page" },
{ value: 100, label: "100 per page" }
]
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
options
- Required (Array) - This defines which the options to add to the dropdown. It must contain the default value based on the search parameters set. Details to20
. Expects objects defining a value and label.-
value
Required (Number) - Number of hits to display per page -
label
Required (String) - Label to display in the option
-
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
selectID
- (String) - Required if the select template is changed to identify the ID of the select field. -
templates
- (Object) - Allows the default templates to be changed-
perPageSelector
- (String) - The template used render the select
-
Pagination Widget
The pagination widget provides the ability to navigate through results pages.
search.addWidget(
search.widgets.pagination({
container: "#pagination-wrapper"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
padding
- (Number) - The number of pages to display on each side of the current page. Defaults to3
. -
showFirstLast
- (Boolean) - Define if the first and last links should be displayed. Defaults totrue
-
hideSinglePage
- (Boolean) - If true, the pagination will be hidden if there is only one page of results. Defaults tofalse
-
scrollTo
- (String | DOMElement | Boolean) - Where to scroll after a click, set to false to disable. Defaults tobody
. -
scrollToTransition
- (Boolean) - If true, the scroll to will transition rather than jump to position. Defaults tofalse
. -
labels
- (Object) - Text to display in the various links (first, previous, next, last).-
first
(String) - Label for the first link -
previous
(String) - Label for the previous link -
next
(String) - Label for the next link -
last
(String) - Label for the last link
-
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the element wrapping the pagination items. Defaults tosupafolio-pagination__wrapper
. -
item
- (String) - The class used for each item. Defaults tosupafolio-pagination__item
. -
link
- (String) - The class used for each item link. Defaults tosupafolio-pagination__link
. -
active
- (String) - The class used for each item which is clickable. Defaults tosupafolio-pagination__item--active
. -
disabled
- (String) - The class used for each item which is not clickable. Defaults tosupafolio-pagination__item--disabled
. -
first
- (String) - The class used for the item which takes the user to the first page. Defaults tosupafolio-pagination__item--first
. -
previous
- (String) - The class used for the item which takes the user to the previous page. Defaults tosupafolio-pagination__item--previous
. -
page
- (String) - The class used for the item which takes the user to a new page. Defaults tosupafolio-pagination__item--pages
. -
next
- (String) - The class used for the item which takes the user to the next page. Defaults tosupafolio-pagination__item--next
. -
last
- (String) - The class used for the item which takes the user to the last page. Defaults tosupafolio-pagination__item--last
.
-
Load More Widget
The load more widget displays a button to load more results. It will display the results as one continuous long page. It's usage is particularly recommended in a mobile context. Even though it is not incompatible, it does not go well with the pagination widget.
search.addWidget(
search.widgets.loadMore({
container: "#load-more-wrapper"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
preloader
- (Boolean) - If false, no preloader will be rendered when the button is clicked. Defaults totrue
. -
label
- (String) - The text label of the button. -
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the div wrapping the button. Defaults tosupafolio-load-more__wrapper
. -
disabled
- (String) - The class used for button is disabled i.e. when there are no more pages to load. Defaults to"supafolio-load-more__wrapper--disabled
. -
button
- (String) - The class used for load more button. Defaults tosupafolio-load-more__button
.
-
NOTE: A load more widget must be linked to the results widget using the loadMore
option of the results widget.
Stats Widget
This widget lets you display how many results matched the query and how fast the search was.
search.addWidget(
search.widgets.stats({
container: "#stats-wrapper"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
statsHandler
- (Function) - Method to change the data passed to the template. A data object must be returned by this method. -
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the div wrapping the stats. Defaults tosupafolio-stats__wrapper
. -
time
- (String) - The class used for query time. Defaults tosupafolio-stats__time
.
-
-
templates
- (Object) - Allows the default templates to be changed-
stats
- (String) - The template used render the stats. Provided withhasManyResults
,hasNoResults
,hasOneResult
,resultsPerPage
,totalResults
,totalPages
,currentPage
,processingTimeMS
andquery
.
-
Clear All Widget
This widget clears the query and all the refinements that are currently applied.
search.addWidget(
search.widgets.clearAll({
container: "#clear-all-wrapper"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
label
- (String) - The text label of the button. -
excludes
- (Array) - Expects an array of Strings. A list of attribute which should not be cleared. -
autoHide
- (Boolean) - Hide the container when no refinements are found. Defaults totrue
. -
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the div wrapping the button. Defaults tosupafolio-clear-all__wrapper
. -
button
- (String) - The class used for clear all button. Defaults tosupafolio-clear-all__button
.
-
Refinement List Filter Widget
This filtering widget lets the user refine the search results. You can specify if you want filters to be OR'ed or AND'ed. For example, if you filter on a
and b
with OR
, results with either the value a
or b
will match.
search.addWidget(
search.widgets.refinementFilter({
container: "#refinement-filter-wrapper",
attribute: "categories.name",
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
attribute
- Required (String) - Name of the attribute to filter against. -
operator
- (String) - How to apply refinements. Possible values:or
,and
,equals
. Theequals
operator is used when you want to create a refinement list where only one filter can be selected at a time. Defaults toor
. -
sortBy
- (Array | Function) - Array of strings expected. Defines how to sort refinements. Possible values:count:asc
,count:desc
,name:asc
,name:desc
,isRefined
. You can also use a sort function that behaves like the standard Javascript compareFunction. Defaults to["isRefined", "name:asc"]
. For instances whereequals
is set as the operator it defaults to["count:desc", "name:desc"]
. -
limit
- (Number) - How many filter values to get. When the show more feature is activated this is the minimum number of filters requested. Defaults to10
. -
showMore
- (Object | Boolean) - Set tofalse
to disable show more button. Set anObject
of options to customise the behaviour of the show more button. Defaults totrue
.- open - (Boolean) - If true, the show more will be open by default. Defaults to
false
. - moreLabel - (String) - The button label when the show more is closed.
- lessLabel - (String) - The button label when the show more is open.
- limit - (Number) - Max number of filter values to display when show more is clicked
- open - (Boolean) - If true, the show more will be open by default. Defaults to
-
collapsible
- (Object | Boolean) - Set totrue
to allow the filter header to hide the body when clicked. Set anObject
of options to customise the behaviour of the collapsible state. Defaults tofalse
.- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
false
.
- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
resultHandler
- (Function) - Method to change the filter passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
header
- (String) - The template used to render the header -
item
- (String) - The template used to render each filter
-
-
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the element wrapping the filter. Defaults tosupafolio-refinement-filter__wrapper
. -
header
- (String) - The class used for the filter header. Defaults tosupafolio-refinement-filter__item--header
. -
body
- (String) - The class used for the filter body. Defaults tosupafolio-refinement-filter__body
. -
list
- (String) - The class used for the list of filters. Defaults tosupafolio-refinement-filter__list
. -
item
- (String) - The class used for each filter. Defaults tosupafolio-refinement-filter__item
. -
active
- (String) - The class used for each filter which is clickable. Defaults tosupafolio-refinement-filter__item--active
. -
single
- (String) - The class used for each filter when the operator isequals
. Defaults tosupafolio-refinement-filter__item--single
. -
multiple
- (String) - The class used for each filter when the operator isor
orand
. Defaults tosupafolio-refinement-filter__item--multiple
. -
link
- (String) - The class used for the filter link. Defaults tosupafolio-refinement-filter__link
. -
button
- (String) - The class used for show more button. Defaults tosupafolio-refinement-filter__show-more-btn
. -
collapsible
- (String) - The class used for the header when collapsible is set totrue
. Defaults tosupafolio-refinement-filter__header--collapsible
.
-
Hierarchical Menu Filter Widget
The hierarchical menu is a widget that lets the user explore a tree-like structure. This is commonly used for multi-level categorisation of products on e-commerce websites. From a UX point of view, we suggest not displaying more than two or three levels deep.
search.addWidget(
search.widgets.hierarchicalMenuFilter({
container: "#hierarchical-menu-wrapper"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
attributes
- (Array) - Expects Strings. Array of attributes to use to generate the hierarchy of the menu. Defaults to["hierarchicalCategories.lvl0", "hierarchicalCategories.lvl1", "hierarchicalCategories.lvl2"]
. -
sortBy
- (Array | Function) - Array of strings expected. Defines how to sort refinements. Possible values:count:asc
,count:desc
,name:asc
,name:desc
,isRefined
. You can also use a sort function that behaves like the standard Javascript compareFunction. Defaults to["isRefined", "name:asc"]
. -
limit
- (Number) - How many filter values to get. When the show more feature is activated this is the minimum number of filters requested. Defaults to10
. -
separator
- (String) - Separator used in the attributes to separate level values. Defaults to>
. -
rootPath
- (String) - Prefix path to use if the first level is not the root level. -
showParentLevel
- (Boolean) - Show the parent level of the current refined value. Defaults totrue
. -
collapsible
- (Object | Boolean) - Set totrue
to allow the filter header to hide the body when clicked. Set anObject
of options to customise the behaviour of the collapsible state. Defaults tofalse
.- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
false
.
- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
resultHandler
- (Function) - Method to change the filter passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
header
- (String) - The template used to render the header -
item
- (String) - The template used to render each filter
-
-
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the element wrapping the filter. Defaults tosupafolio-hierarchical-menu-filter__wrapper
. -
header
- (String) - The class used for the filter header. Defaults tosupafolio-hierarchical-menu-filter__item--header
. -
body
- (String) - The class used for the filter body. Defaults tosupafolio-hierarchical-menu-filter__body
. -
list
- (String) - The class used for the list of filters. Defaults tosupafolio-hierarchical-menu-filter__list
. -
item
- (String) - The class used for each filter. Defaults tosupafolio-hierarchical-menu-filter__item
. -
active
- (String) - The class used for each filter which is clickable. Defaults tosupafolio-hierarchical-menu-filter__item--active
. -
link
- (String) - The class used for the filter link. Defaults tosupafolio-hierarchical-menu-filter__link
. -
collapsible
- (String) - The class used for the header when collapsible is set totrue
. Defaults tosupafolio-hierarchical-menu-filter__header--collapsible
.
-
Numeric Refinement Filter Widget
This widget lets the user refine search results based on a numerical attribute. You can specify a specific number or a range.
search.addWidget(
search.widgets.numericRefinementFilter({
container: "#numeric-refinement-wrapper",
attribute: "prices.GBP",
filters: [
{name: 'All' },
{ end: 7.48, name: 'less than £7.49' },
{ start: 7.49, end: 7.49, name: 'exactly £7.49' },
{ start: 7.50, name: 'more than £7.49' }
]
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
attribute
- Required (String) - Name of the attribute to filter against. -
filters
- Required (Array) - This defines the filters to render. Expects objects defining a name. If nostart
orend
is defined the filter will clear the refinement.-
name
Required (String) - The name of the filter -
start
(Number) - Low bound of the option (>=) -
end
(Number) - High bound of the option (<=)
-
-
collapsible
- (Object | Boolean) - Set totrue
to allow the filter header to hide the body when clicked. Set anObject
of options to customise the behaviour of the collapsible state. Defaults tofalse
.- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
false
.
- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
resultHandler
- (Function) - Method to change the filter passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
header
- (String) - The template used to render the header -
item
- (String) - The template used to render each filter
-
-
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the element wrapping the filter. Defaults tosupafolio-numeric-refinement-filter__wrapper
. -
header
- (String) - The class used for the filter header. Defaults tosupafolio-numeric-refinement-filter__item--header
. -
body
- (String) - The class used for the filter body. Defaults tosupafolio-numeric-refinement-filter__body
. -
list
- (String) - The class used for the list of filters. Defaults tosupafolio-numeric-refinement-filter__list
. -
item
- (String) - The class used for each filter. Defaults tosupafolio-numeric-refinement-filter__item
. -
active
- (String) - The class used for each filter which is clickable. Defaults tosupafolio-numeric-refinement-filter__item--active
. -
link
- (String) - The class used for the filter link. Defaults tosupafolio-numeric-refinement-filter__link
. -
collapsible
- (String) - The class used for the header when collapsible is set totrue
. Defaults tosupafolio-numeric-refinement-filter__header--collapsible
.
-
Toggle Filter Widget
This widget provides an on/off filtering feature based on an attribute value. Note that if you provide an “off” option, it will be refined at initialisation.
search.addWidget(
search.widgets.toggleFilter({
container: "#toggle-wrapper",
attribute: "primaryFormat",
filter: {
label: "is primary format?",
on: 1
}
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
attribute
- Required (String) - Name of the attribute to filter against. -
filter
- Required (Object) - This defines the filter to render. Expects objects defining a label.-
label
Required (String) - The label of the filter -
on
(Number | Boolean | String) - The value to filter on when checked. Defaults totrue
. -
off
(Number | Boolean | String) - Value to filter on when unchecked. By default when switching tooff
, no refinement will be asked. So you will get bothtrue
andfalse
results. If you set the off value tofalse
then you will get only objects havingfalse
has a value for the selected attribute.
-
-
collapsible
- (Object | Boolean) - Set totrue
to allow the filter header to hide the body when clicked. Set anObject
of options to customise the behaviour of the collapsible state. Defaults tofalse
.- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
false
.
- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
resultHandler
- (Function) - Method to change the filter passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
header
- (String) - The template used to render the header -
item
- (String) - The template used to render each filter
-
-
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the element wrapping the filter. Defaults tosupafolio-toggle-filter__wrapper
. -
header
- (String) - The class used for the filter header. Defaults tosupafolio-toggle-filter__item--header
. -
body
- (String) - The class used for the filter body. Defaults tosupafolio-toggle-filter__body
. -
item
- (String) - The class used for each filter. Defaults tosupafolio-toggle-filter__item
. -
active
- (String) - The class used for each filter which is clickable. Defaults tosupafolio-toggle-filter__item--active
. -
link
- (String) - The class used for the filter link. Defaults tosupafolio-toggle-filter__link
. -
collapsible
- (String) - The class used for the header when collapsible is set totrue
. Defaults tosupafolio-toggle-filter__header--collapsible
.
-
Range Slider Filter Widget
The range slider widget lets users filter results within a numerical range, based on an attribute. The min and max values are automatically computed using the data in the index.
search.addWidget(
search.widgets.rangeSliderFilter({
container: "#range-slider-wrapper",
attribute: "prices.GBP"
})
);
Options
-
container
- Required (String | DOMElement) - CSS selector or DOM element defining where the widget will be rendered. -
attribute
- Required (String) - Name of the attribute to filter against. -
pips
- (Boolean | Object) - Show slider pips. Defaults totrue
.-
density
(Number) - The number of pips -
values
(Array) - Expects Numbers. At which percentage to show a labelled pip
-
-
tooltips
- (Boolean | Function) - Method to format the tooltips show above the slider handles Set tofalse
to disable tooltips. Defaults totrue
, -
step
- (Number) - Every handle move will jump that number of steps. Note if set to0
the slider will be fluent. Defaults to1
, -
dragRange
- (Boolean) - Set tofalse
to disable the drag on the range between the min and max handles. Defaults totrue
, -
collapsible
- (Object | Boolean) - Set totrue
to allow the filter header to hide the body when clicked. Set anObject
of options to customise the behaviour of the collapsible state. Defaults tofalse
.- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
false
.
- collapsed - (Boolean) - If true, the filter will be closed by default. Defaults to
-
autoHide
- (Boolean) - Hide the container when no results match. Defaults totrue
. -
resultHandler
- (Function) - Method to change the filter passed to the template. A data object must be returned by this method. -
templates
- (Object) - Allows the default templates to be changed-
header
- (String) - The template used to render the header -
item
- (String) - The template used to render each filter
-
-
classes
- (Object) - Allows the default css classes to be changed-
wrapper
- (String) - The class used for the element wrapping the filter. Defaults tosupafolio-range-slider-filter__wrapper
. -
header
- (String) - The class used for the filter header. Defaults tosupafolio-range-slider-filter__item--header
. -
body
- (String) - The class used for the filter body. Defaults tosupafolio-range-slider-filter__body
. -
slider
- (String) - The class used for the slider container. Defaults tosupafolio-range-slider-filter__link
. -
collapsible
- (String) - The class used for the header when collapsible is set totrue
. Defaults tosupafolio-range-slider-filter__header--collapsible
.
-
Cheatsheet
Templates
Providing templates
Passing in a big template string into the widget config can tend to get quite unmanageable, especially for the full details widget. Instead, create your template in a script tag with an ID and then select that in the widget config e.g.
<script type="text/html" id="item-template">
<div class="supafolio-details-item">
<div class="supafolio-details-item__image-wrapper">
<img class="supafolio-details-item__image" src="{{item.image}}" alt="{{item.title}}" />
</div>
<div class="supafolio-details-item__content">
<h1 class="details-item__title">{{item.title}}</h1>
<h2 class="details-item__subtitle">{{item.subtitle}}</h2>
<h3 class="details-item__contributor-by-line">{{item.contributorByLine}}</h3>
<div class="details-item__description">{{{item.description}}}</div>
</div>
</div>
</script>
client.addDetailsWidget({
container: "#product-details-wrapper",
objectID: "9781447294627",
source: "product",
templates: {
item: document.querySelector("#item-template").innerHTML
}
});
Rendering HTML values in templates
The templates engine uses Handlebars JS, it uses expressions to render data properties. This is done with the use of curly braces, For example, {{title}}
would print the title property in the current context. The use of 2 curly braces tells handlebars to print the value as plain text. If the data property contains HTML you can use 3 curly braces to let handlebars know is needs to evaluate the html when it's printed. i.e. {{{description}}}
.
For more information please see the documentation
Looping data in templates
To loop through a data array or object you can use the built-in each
helper.
For arrays:
{{#each myArray}}
Index: {{@index}} Value = {{this}}
{{/each}}
For objects:
{{#each myObject}}
Key: {{@key}} Value = {{this}}
{{/each}}
For more information please see the documentation
Helpers
Date manipulation
Convert a timestamp to a formatted date string
client.helpers.formatTimestamp( 1484197200 );
// Outputs: 12/01/2017
Convert a timestamp to a formatted date string
client.helpers.formatTimestamp( 1484197200 );
// Outputs: 12/01/2017
client.helpers.formatTimestamp( 1484197200, "y-m-d" );
// Outputs: 2017-12-01
Convert a Date to a formatted date string
client.helpers.formatDate( new Date( "12/01/2017" ) );
// Outputs: 12/01/2017
client.helpers.formatDate( new Date( "12/01/2017" ), "y-m-d" );
// Outputs: 2017-12-01
Convert a timestamp to a Date
client.helpers.convertTimestampToDate( 1484197200 );
// Outputs: Thu Jan 12 2017 05:00:00 GMT+0000 (GMT)
Get a timestamp for the start of a date i.e. 00:00:00 of that day - useful for filtering by dates i.e. coming soon
on ecommerce websites
client.helpers.getStartOfDate( client.helpers.convertTimestampToDate( 1484197200 ) );
// Outputs: 1484179200000
Get a timestamp for the end of a date i.e. 23:59:59 of that day - useful for filtering by dates i.e. coming soon
on ecommerce websites
client.helpers.getEndOfDate( client.helpers.convertTimestampToDate( 1484197200 ) );
// Outputs: 1484265599999
String manipulation
Convert a string to an SEO friendly string - useful for adding data to urls
client.helpers.seoURL( "The messy title's of Books! - part 1..." );
// Outputs: the-messy-titles-of-books-part-1
Resize an image URL (Note, this will only work for Supafolio's image service)
client.helpers.resizeImage( "https://timeinc-us.imgix.net/covers/9781618931566.jpg?w=298", 350 );
// Outputs: https://timeinc-us.imgix.net/covers/9781618931566.jpg?w=350
Custom searches
Get a product by ISBN
search.getByISBN( "9781447294627" ).then( result => {
if( !result.length ) {
console.error( "Not found" );
return;
}
const product = result.shift();
} );
Execute a custom search
search.execute( {
params: {
query: "search",
hitsPerPage: 3
}
} ).then( result => {
if( !result.hits || !result.hits.length ) {
console.error( "Not found" );
return;
}
const results = result.hits;
} );
Execute a multiple custom searches
search.execute( [
{
params: {
query: "search 1",
hitsPerPage: 3
}
},
{
params: {
query: "search 2",
hitsPerPage: 3
}
}
] ).then( response => {
let results1 = response.results[0];
let results2 = response.results[1];;
if( !results1.hits || !results1.hits.length ) {
console.error("Search 1 not found");
}
if( !results2.hits || !results2.hits.length ) {
console.error("Search 2 not found");
}
results1 = results1.hits;
results2 = results2.hits;
} );
Styles
Change the colour of the load more preloader
.supafolio-load-more__preloader {
border-top-color: rgba(#FFF, 0.65);
border-bottom-color: rgba(#FFF, 0.15);
border-left-color: rgba(#FFF, 0.65);
border-right-color: rgba(#FFF, 0.15);
}
Rule uses for grid columns
.supafolio-grid-columns {
bottom: 0;
box-sizing: border-box;
display: inline-block;
padding: 0 2%;
vertical-align: top;
}
FAQ
- How do I initialise the library?
Simply pass you account details into supafolio
const client = supafolio( "LZ2Q6SA8YD", "2ed4b5c343fb7251f8a86c87ae3e8b76", "demo" );
- Are there any concerns about JavaScript Delivered Content and SEO?
We recommend all data come through the front-end, served by JavaScript. We recommend this because it is much better for the user experience and happy users are returning users.
In the past, there has been a big concern that web crawlers are unable to see this content. But in 2015, Google announced that they indeed can see it. It is important to note, however, that Google still recommends having individual URLs for the “pages” that the JavaScript response creates.
To do this, you will use the browser APIs that allow you to manipulate the browser history. This is also a good UX principle independent of the SEO benefits (which is generally the case!). Note that we do this automatically with our Search results widget when URL sync is enabled.
However, as the URL above mentions, if you want to be 100% safe then you can pre-render pages on the backend and serve it up to the search engine crawlers. This will increasingly be unnecessary as the web crawlers get better at executing JavaScript.
License
- Proprietary software license
- Copyright 2016 © Supadü.