Just wait an Instant Moment.JS!
A look at using Algolia Instantsearch.js along with MomentJS to create an events search.
I recently posted ‘A look into the new Keele University website search’ and wanted to expand on this here with a short overview of how the cloud search service Algolia was also used as an events system along with Terminalfour, Keele’s chosen CMS.
The legacy Keele website had grown slowly over a number of years and one of the results of this was a disparate set of events pages that were often buried in amongst multiple areas of the site. The University have events across alumni, arts and culture, schools and faculties, business, public lectures as well as conferences, graduation ceremonies and open days. With our website users in mind, we wanted to bring all of these events into one place. Behind the scenes, our internal staff in various areas of the University would produce the events pages but the internal structures would be invisible to the website visitor. Visitors should then be able to simply view upcoming events at Keele University. There were many ways to achieve this but since we already had a subscription to Algolia and a method in our CMS to pull in data using ‘navigation objects’ we already had all the tools to create something in house at low cost.
TL;DR
This article is a little more technical than the last but can be summarised as
- CMS based: create an ‘Event’ Content Type’with required fields for an event title, snippet and start date. Also an optional field for end date. Collect and export all events data as JSON ready to feed to Algolia but during export, convert all dates to linux timestamps using t4 programmable layouts (using Rhino/JavaScript).
- Algolia based: Using IntantSearch.js library, fire the search using user entered search termsand human readable start/end datesmapped to unix timestamps.
- Frontend JavaScript and JS helpers: Convert human readable dates to unix timestampsusing vanilla JavaScript along with the JS utility, MomentJS to allow easy manipulation of datesand the lightweight JavaScript Pikaday for a cross browser datepicker dropdown.
I’ll go into a little more depth below.
Using VueJS alongside Algolia and the data formatting of t4 has come together nicely and has given a simple and maintanable solution that meets the requirements of what our users were asking for during the research and planning stage of the web project.
Creating an ‘events’ content type
Each content type in our CMS can be output using multiple formatters. For example, the homepage can selectively output just an event title and snippet from an instance of an event content type, while the event page that it links to can display the title, image, description and booking links. A content type can also output content in JSON format (or any format) and in our case here, there’s an extra layer available that allows the programmatic output of user entered fields. So whereas typical formatters output content surrounded by html tags, programmable layouts are useful for doing things like converting data and then outputting JSON.
// example of programmatically outputting one property from a user entered date element -> JSON// Retrieve the user entered date using t4 date format - yyyy/MM/d k:m
var eventStartDateElement = '<t4 date_format="yyyy/MM/d k:m" type="content" name="Start Date" output="normal" />';
// make the value usable in the programmable layout using
var eventStartDate = BrokerUtils.processT4Tags (dbStatement, publishCache, section, content, language, isPreview, eventStartDateElement);// now use the eventDate element from the template - converting it to a unix timestamp
var unixEventStartDate = Math.round(new Date(eventStartDate).getTime()/1000);// Output json
document.write("{"); // begin json object
//...
document.write('"unixStartDate": ' + unixEventStartDate + ','); // output date property to search against in Algolia
//... additional properties such as title etc// The above can be done for all the other fields/properties but
// we need to make sure we output a number instead of NaN if there is no endDate
if ( isNaN(unixEventEndDate) ) {
unixEventEndDate = 0;
}
The //comments in the gist above explain how data is taken from the CMS, processed and output as JSON. Note that the endDate is not always required for an event and so we set it to an integer (0) if it has not been entered by the CMS editor.
Categories were listed as tags in the JSON and available to our CMS editors via check boxes. Here’s an example output for a single event that has no end date (the event is on one day only) and appears only in one category.
Searching events and data ranges
When a user lands on the events search page, they’re presented with an input search box as well as a start and end date dropdown. To auto populate the start date to today and the end date to two months in the future, we use JS and Moment.
var today = new Date();// use Moment.JS to auto set the default 'to' date 2 months ahead
var monthAhead = moment().add(2, 'months').format('MM/DD/YYYY');
//... // alter Pikaday start and end date for default search range on page load
pickerFrom.setDate(today);
pickerTo.setDate(monthAhead);
//...
For the categories, I hooked up checkboxes to a Vue property using v-model. This then gave a reactive filter term that could be used to trigger a new Algolia search when the user clicks on a category.
Algolia has a filters parameter that can filter results with SQL-like syntax. Based on the events requirements for Keele, I created the following logic:
filters: ‘(unixStartDate:’ + this.searchFrom + ‘ TO ‘ + this.searchTo + ‘) OR (unixEndDate:’ + this.searchFrom + ‘ TO ‘ + this.searchTo + ‘) AND (‘ + this.checkedCategoriesString + ‘ )’,
So we’re searching for all events that have a startDate OR an endDate within the specified date range AND match any selected categories.
//... Vue component for events search
export default {
name: "algEventsMain",
data () {
return {
searchFrom: 0,
searchTo: 0,
pickerFrField: 0,
pickerToField: 0,
eventArray: [],
eventArrayLength: 0,
searchQuery: '',
checkedCategories: []
page: 0
}
},
//... etc methods: {
//... Algolia search method passing Vue data into the filter term
searchMethod: function () {
filters: '(unixStartDate:' + this.searchFrom + ' TO ' + this.searchTo + ') OR (unixEndDate:' + this.searchFrom + ' TO ' + this.searchTo + ') AND (' + this.checkedCategoriesString + ' )',
//...
Frontend JS helpers: Pikaday, MomentJS…
Pikaday gave us a lightweight and quick way to add cross browser, accessible, styleable date pickers with full IE support and additional methods. Recording the dates in the Vue instance then passed the values onto the Algolia filter.
MomentJS made it easy to convert various date formats as required.
As always, a huge thank you to the maintainers of these open source libraries.
Let’s call it a date range
The search results from Algolia are formatted on our search page using Algolia template syntax. Similar to the course search mentioned in the previous post. The elements are referenced using mustache syntax and results are looped through using Vue’s v-for
directive. This allowed us to inject the results into the designs and pattern library that we received from Absolute, the digital agency we worked with throughout the project.
Feedback on the new events search
The events page has been an interesting part of the project and a great opportunity to bring together many events from across the University into one place using just one technical system.
The research found that users were confused by the old events section of the site, especially how lecture events were categorised. Stream lining the categories and pulling the events onto one top level search page has given more prominence and discoverability to events at Keele University. Design wise, we also had the brilliant and modern responsive pattern library from our agency Absolute.
Since the launch, we have added additional navigation objects that display specific categories on specific, high traffic landing pages. An example being the Keele Music Events page. This feeds from the centrally maintained list of events that appear in the search results page.
For events that have passed I’ve also implemented a time based script that divides events on the year and month pages under past and upcoming headings.