Here is how to deploy the following example, step by step:
Deploy to Heroku by clicking the button
This requires a verified Heroku account—you will have to add a payment method to Heroku even though you won't be charged
Run this command in the terminal window:
heroku run -a sh-example-simple soulheart load https://raw.githubusercontent.com/sethherr/soulheart/master/examples/manufacturers_simple.tsv
sh-example-simple
with the name of your app on HerokuAdd Select2 by loading the source from a CDN:
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" /> <script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
... and a select box to your html page:
<select id="basic-example-select"></select>
Use this javascript to hook up the select box with select2:
$('#sh-example-simple-select').select2({ allowClear: true, placeholder: "Choose a manufacturer", ajax: { url: "http://sh-example-simple.herokuapp.com", dataType: "json", width: 'style', delay: 250, data: function(params) { return { q: params.term, page: params.page, per_page: 10 }; }, processResults: function(data, page) { return { // Select2 requires an id, so we need to map the results and add an ID // You could instead include an id in the tsv you add to soulheart ;) results: data.matches.map(function(item) { return { id: item.text, text: item.text }; }), pagination: { // If there are 10 matches, there's at least another page more: data.matches.length === 10 } }; }, cache: true } });
sh-example-simple
in http://sh-example-simple.herokuapp.com
with the name of your app on HerokuSo, for example, let’s say you want to select bicycle manufacturers using select2 - but you want to prioritize more common manufacturers.
Some manufacturers are more popular than others - and since we expect people to be searching for more popular ones more frequently, it’s important to make them show up first — for example, if you input a “t”, the first manufacturer to select should be “Trek”, not “Tacx”.
Items with equal scores are ordered alphanumerically. So in the manufacturers example above, manufacturers are grouped in broad levels of popularity - 10, 100, 250 & 500 - higher numbers show up first. This example uses manufacturers.tsv
Set a priority
to organize the way items are ordered.
$('#sh-example-priority-select').select2({ allowClear: true, width: 'style', placeholder: "Choose manufacturers", multiple: true, ajax: { url: "https://sh-example-priority.herokuapp.com", dataType: 'json', delay: 250, data: function(params) { var result; return result = { q: params.term, page: params.page, per_page: 10 }; }, processResults: function(data, page) { return { results: data.matches, pagination: { more: data.matches.length === 10 } }; }, cache: true } });
Search for items in only one category by adding a category
parameter.
This example uses categories.json, which includes a whole host of options from the Bike Index API. Say that, instead of searching the full list, you only want to view options for handlebar types.
All categories are available at the Heroku app’s url + /categories
. So start by pulling options into the category select box from:
https://sh-example-categories.herokuapp.com/categories
When the category changes, you want to grab the value and add it to your url as a query. This becomes the source for the items select box:
https://sh-example-categories.herokuapp.com?categories=handlebar%20types
Search for items in multiple categories by separating them with commas:
https://sh-example-categories.herokuapp.com?categories=colors,component%20types
$('#sh-example-categories-select-category').select2({ allowClear: true, width: 'style', placeholder: "Choose a category", multiple: true, ajax: { url: "https://sh-example-categories.herokuapp.com/categories", dataType: 'json', delay: 250, data: function(params) { return { q: params.term, page: params.page, per_page: 10 }; }, processResults: function(data, page) { return { results: data.categories.map(function(item) { return { id: item, text: item }; }) }; }, cache: true } }); $('#sh-example-categories-select-category').on("change", function(e) { if ($(this).val() === null) { $('#sh-example-categories-select-item').select2('val', 'All'); } window.categories = $(this).val(); window.categories_url = toQueryString(window.categories); setItemsSelect(window.categories_url); return setLabelText(window.categories); }); setItemsSelect = function(categories_url) { return $('#sh-example-categories-select-item').select2({ allowClear: true, width: 'style', multiple: true, placeholder: "Choose items", ajax: { url: categories_url, dataType: 'json', delay: 250, data: function(params) { return { q: params.term, page: params.page, per_page: 10 }; }, processResults: function(data, page) { return { results: data.matches.map(function(item) { return { id: item.text, text: item.text }; }), pagination: { more: data.matches.length === 10 } }; }, cache: true } }); };
Any column that isn’t category
, text
or priority
will be returned as well.
Here, the emoticons.tsv example file includes id
, image_url
and source
fields. These values are returned and available for incorporation into the select box.
Through the magic of select2’s templating options, emoticon images are displayed in the dropdown along with their text
, category
and source
details:
formatEmoji = function(emoji) { if (emoji.category === "emoticon") { $emoji = $("<span><img src='" + emoji.image_url + "' class='img-emoji opt-emoji' />" + emoji.text + "</span><span class='emoji-type'>" + emoji.category + " from " + emoji.source + "</span>"); return $emoji; } };
Once an item is selected, we can opt to display only its image:
formatSelectedEmoji = function(emoji) { if (emoji.category === "emoticon") { $emoji = $("<span><img src='" + emoji.image_url + "' class='img-emoji' /></span>"); return $emoji; } };
To match the dongers and emoticons, Soulheart needs to not ignore symbols. Typically Soulheart strips out symbols to make matching easier, but you can change the normalizing function with a command
In this case, to load in the dongers and emoticons, the exact commands (after creating a Heroku instance named sh-example-arbitrary
):
heroku run -a sh-example-arbitrary "soulheart -s normalize"
heroku run -a sh-example-arbitrary soulheart load https://raw.githubusercontent.com/sethherr/soulheart/master/examples/emoticons.tsv
$('#sh-example-arbitrary-select').select2({ allowClear: true, width: 'style', placeholder: "Choose an emoticon", multiple: true, templateSelection: formatSelectedEmoji, templateResult: formatEmoji, ajax: { url: "https://sh-example-arbitrary.herokuapp.com", dataType: 'json', delay: 250, data: function(params) { return { q: params.term, page: params.page, per_page: 10 }; }, processResults: function(data, page) { return { results: data.matches, pagination: { more: data.matches.length === 10 } }; }, cache: true } }); formatEmoji = function(emoji) { var $emoji; if (!emoji.id) { return emoji.text; } if (emoji.category === "emoticon") { $emoji = $("<span><img src='" + emoji.image_url + "' class='img-emoji opt-emoji' />" + emoji.text + "</span><span class='emoji-type'>" + emoji.category + " from " + emoji.source + "</span>"); return $emoji; } else if (emoji.category === "donger") { $emoji = $("<span><span class='img-donger opt-emoji'>" + emoji.text + "</span>" + emoji.id + "</span><span class='emoji-type'>" + emoji.category + " from " + emoji.source + "</span>"); return $emoji; } }; formatSelectedEmoji = function(emoji) { var $emoji; if (!emoji.id) { return emoji.text; } if (emoji.category === "emoticon") { $emoji = $("<span><img src='" + emoji.image_url + "' class='img-emoji' /></span>"); return $emoji; } else if (emoji.category === "donger") { $emoji = $("<span class='img-donger'>" + emoji.text + "</span>"); return $emoji; } };