Created
January 2, 2015 19:33
-
-
Save ranelpadon/cd8d7d0d734d24b53c5f to your computer and use it in GitHub Desktop.
Sample integration of Twitter TypeAhead Library with a remote data server (TripAdvisor API).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MAPWIDGET = MAPWIDGET || {}; | |
// Constructor function for TripAdvisor's TypeAhead behavior. | |
MAPWIDGET.Autocomplete = function(domElement) { | |
// TypeAhead Source URL per documentation of TripAdvisor. | |
// See http://api.tripadvisor.com/api/partner/2.0/doc?key=TA_KEY. | |
// %QUERY is a wildcard needed by the suggestion engine. | |
var typeAheadUrl = TripAdvisor_API_BASE_URL + '/typeahead/%QUERY?key=' + tripAdvisorKey; | |
// Create a new suggestion engine dedicated for the specified category. | |
function suggestionEngine(category) { | |
// Create a new BloodHound suggestion engine. | |
// See https://github.com/twitter/typeahead.js for API. | |
var places = new Bloodhound({ | |
// Data Source for the suggestion engine. | |
// Other options: "local" and "prefetch". | |
remote: { | |
url: typeAheadUrl, | |
// Fetch the TripAdvisor's JSON object. | |
// Filter the information that will be displayed. | |
filter: function (places) { | |
// Get the current text of the search field. | |
var currentText = jQuery('input.tt-input').val(); | |
// Check if the currently searched Place name has no returned results. | |
// And it should not consider already selected Place name. | |
// The selected Place name contains left and right parentheses. | |
if (jQuery.isEmptyObject(places) && currentText.indexOf("(") == -1) { | |
// Modify the search bar to indicate a no result behavior. | |
// This is a light orange color to slighty blend with the generally | |
// white and gray elements of the Dialog window. | |
MAPWIDGET.Autocomplete.display_error(); | |
} | |
// If there's a result, revert to the default color. | |
// This is necessary especially to switch back from orange color | |
// to transparent color. | |
else { | |
MAPWIDGET.Autocomplete.display_default(); | |
} | |
// Get the index of "-" char if any. | |
var dashIndex = jQuery('input.tt-input').val().indexOf("-"); | |
// If the current Place is not found in the TripAdvisor servers, | |
// check if it has a dash on it. Truncating the dash works | |
// for some specific Place names. | |
if (jQuery.isEmptyObject(places) && dashIndex != -1) { | |
// Remove the dash. | |
cleaned = jQuery('input.tt-input').val().replace(/-/g, ""); | |
// Modify the currently searched Place name. | |
jQuery('input.tt-input').typeahead("val", cleaned); | |
} | |
// Check if there's at least one search result in the | |
// current category. Categories are 'Attractions', 'Hotels', | |
// and 'Restaurants'. Not using this check will throw a bunch | |
// of annoying console error notices, and will make the autocomplete | |
// to behave erratically after some time. | |
if (places.hasOwnProperty(category)) { | |
// Fetch the target category only. | |
return $.map(places[category], function (place) { | |
// Container for City name, since we want to include | |
// this information to minimize ambiguity | |
// between Places of the same name. | |
var city = ""; | |
// Check if the current Place has a defined City name. | |
if (place.address_obj.city != "" && place.address_obj.city != null) { | |
city = place.address_obj.city; | |
} | |
var address = ""; | |
// Check if the current Place has a defined City name. | |
if (place.address_obj.address_string != "" && place.address_obj.address_string != null) { | |
address = place.address_obj.address_string; | |
} | |
// Build the suggestion item for the current Place. | |
// Include the City name to avoid ambiguity. | |
var suggestion = (city != "") ? place.name + " (" + city + ")": place.name; | |
return { | |
// Set the property of each Place object | |
// that will be displayed in the autosuggestion. | |
// This will display the names of Places. | |
// City and Location ID will be not displayed in | |
// the suggestions list but will be used behind the scenes. | |
// Luckily, Twitter TypeAhead API has this clever mechanism | |
// yet not clearly documented on its site. | |
// This set of information could be retieved later in real-time | |
// via the suggestion obejct when the "typeahead:selected" and | |
// "typeahead:autocompleted" events have been fired. | |
// At a minimum, this object must have a "value" parameter/key. | |
"value": suggestion, | |
"city": city, | |
"address": address, | |
"locationId": place.location_id | |
}; | |
}); | |
} | |
// This part is very important. This is the handler for cases | |
// with no search results. | |
else { | |
return { | |
// Return an empty object. That's it. | |
// These combinations will not work: | |
// return { value: "" }, or retun { value: null }. | |
}; | |
} | |
} | |
}, | |
// Transform the data source into an array of string tokens. | |
// This is a required parameter. | |
datumTokenizer: function (datum) { | |
return Bloodhound.tokenizers.whitespace(datum.value); | |
}, | |
// Transform the search query into an array of string tokens. | |
// This is a required parameter. | |
queryTokenizer: Bloodhound.tokenizers.whitespace, | |
}); | |
return places; | |
} | |
var categories = ["attractions", "hotels", "restaurants"]; | |
var len = categories.length; | |
var places_datasets = []; | |
// Do some TypeAhead pre-processing needed. | |
for (var i = 0; i < len; i++) { | |
// Create a new suggestion object. | |
var places = suggestionEngine(categories[i]); | |
// Load/initialize the suggestion engine for this Place. | |
places.initialize(); | |
// Create a new object for storing TypeAhead dataset and its options. | |
var dataset = {}; | |
// Format the sub-group name/header to be displayed. | |
var firstWordCapitalized = categories[i].charAt(0).toUpperCase() + categories[i].slice(1); | |
// Add template for displaying the autosuggestion's sub-groups. | |
dataset.templates = {header: '<h4 class="place_group">' + firstWordCapitalized + '</h4>'} | |
//dataset.templates = {footer: '<p class="search-more">Search More Results</p>'} | |
// Set the TypeAhead's data source. | |
dataset.source = places.ttAdapter(); | |
// Add to the existing TypeAhead datasets. | |
places_datasets.push(dataset); | |
} | |
// Convert the text field as a typeahead object. | |
// Set the hint and highlighting behavior in the suggestions list, | |
// as well as the minimum number of characters typed by a user before | |
// the typeahead engine will kick-in. | |
domElement.typeahead({ | |
hint: true, | |
highlight: true, | |
minLength: 3 | |
}, | |
places_datasets | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment