Skip to content

Instantly share code, notes, and snippets.

@bland-industries
Last active February 17, 2016 15:10
Show Gist options
  • Save bland-industries/5c08b0637901fc08e52e to your computer and use it in GitHub Desktop.
Save bland-industries/5c08b0637901fc08e52e to your computer and use it in GitHub Desktop.
Built this search function with auto complete from ajax. Somewhat specific to my needs but can be adapted to others. The server site is up to you.
<input type="text" id="searchBox" style="width:300px" class="input-xlarge" />
<div id='resultContainer'></div>
<script type="text/javascript" scr='/search.js'></script>
<script type="text/javascript">
FundSearch.Presenter.create('#searchBox', '#resultContainer', '/search.php');
</script>
var Observer = {
add: function (obj) {
var eventBroker = {};
obj.bind = function bind(eventName, handler) {
if (eventName in eventBroker) {
eventBroker[eventName].push(handler);
} else {
eventBroker[eventName] = [];
eventBroker[eventName].push(handler);
}
};
obj.trigger = function trigger(eventName) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < eventBroker[eventName].length; i++) {
eventBroker[eventName][i].apply(this, args);
}
};
obj.unbind = function unbind(eventName, handler) {
if (eventBroker[eventName] !== undefined) {
var handlerIndex = eventBroker[eventName].indexOf(handler);
if (handlerIndex > -1) {
eventBroker[eventName].splice(handlerIndex, 1);
}
}
};
return obj;
}
};
var FundSearch = {};
FundSearch.View = {
create: function (searchBoxSel, resultContainerSel) {
var view = Observer.add({});
searchBox = $(searchBoxSel);
resultContainer = $(resultContainerSel);
view.getSearchTerm = function() {
return searchBox.val();
}
function moveHighlight(selected, newSelected, contingency) {
if (selected.length) {
selected.toggleClass("js_selectedSearch");
if (newSelected.length) {
newSelected.toggleClass("js_selectedSearch");
} else {
resultContainer.find("ul a:" + contingency).addClass("js_selectedSearch");
}
} else {
resultContainer.find("ul a:" + contingency).addClass("js_selectedSearch");
}
}
view.highlightNextSearch = function() {
selected = resultContainer.find(".js_selectedSearch");
newSelected = selected.next();
contingency = "first-child";
moveHighlight(selected, newSelected, contingency);
}
view.highlightPrevSearch = function() {
selected = resultContainer.find(".js_selectedSearch");
newSelected = selected.prev();
contingency = "last-child";
moveHighlight(selected, newSelected, contingency);
}
view.clickSearchLink = function () {
selected = resultContainer.find(".js_selectedSearch");
if (!selected.length) {
selected = resultContainer.find("ul a:first-child");
}
if (selected.length) {
selected[0].click();
}
}
searchBox.keyup(function (e) {
if (e.keyCode != 38 && e.keyCode != 40 && e.keyCode != 13) {
view.trigger('searchBoxKeyUp');
}
e.preventDefault(); // prevent the default action (scroll / move caret)
});
$(document).keydown(function(e) {
switch(e.which) {
case 38: // up
view.trigger('arrowUpKeyUp');
searchBox.blur();
break;
case 40: // down
view.trigger('arrowDownKeyUp');
searchBox.blur();
break;
case 13: //enter
view.trigger('enterKeyUp');
break;
default: return; // exit this handler for other keys
}
e.preventDefault(); // prevent the default action (scroll / move caret)
});
// This is where the list is being built. This will change as the designer needs to change things.
view.updateSearchResults = function (results) {
string = "SearchTerm: " + results.searchTerm + "<br>";
string += "<ul>";
for (var i = 0; i < results.results.length; i++) {
string += "<a href='/fund/" + results.results[i].id + "'>"
string += "<li>"
string += ": " + results.results[i].firm;
string += ": " + results.results[i].name;
if (results.results[i].tickers.charAt(0) != ",") {
string += ": " +results.results[i].tickers;
}
string += "</li></a>";
};
string += "</ul>";
resultContainer.html(string);
}
return view;
}
};
FundSearch.Presenter = {
create: function (searchBoxSel, resultContainerSel, theURL) {
var presenter = {};
var model = FundSearch.Model.create(theURL);
var view = FundSearch.View.create(searchBoxSel, resultContainerSel);
waiting = false;
function makeSearching () {
searchTerm = view.getSearchTerm();
if (searchTerm.length >= 3) {
model.newSearch(searchTerm);
}
waiting = false;
}
function updateSearchResults(results) {
currentSearchTerm = view.getSearchTerm();
if (currentSearchTerm == results.searchTerm) {
view.updateSearchResults(results);
}
}
// user types into the search box
view.bind('searchBoxKeyUp', function(){
if (!waiting) {
waiting = true;
setTimeout(makeSearching, 250);
}
})
// user presses the up arrow key
view.bind('arrowUpKeyUp', function(){
if (!waiting) {
view.highlightPrevSearch();
}
})
// user presses the down arrow key
view.bind('arrowDownKeyUp', function(){
if (!waiting) {
view.highlightNextSearch();
}
})
// user presses the enter key
view.bind('enterKeyUp', function(){
if (!waiting) {
view.clickSearchLink();
}
})
// And the results are in boys and girls.
model.bind('resultsIn', function (results){
view.updateSearchResults(results);
})
}
};
FundSearch.Model = {
create: function (theURL) {
var model = Observer.add({});
// cache the search results
searchList = {};
model.newSearch = function (searchTerm) {
if (!(searchTerm in searchList)) {
data = {"searchTerm": searchTerm};
$.ajax ({
url: theURL,
type: "POST",
dataType: "json",
data: data,
success: successFunc,
error: errorFunction,
});
} else {
// return cached data
successFunc(searchList[searchTerm]);
}
};
function successFunc (result) {
// Currently does not inform user of success of form submission
searchList[result.searchTerm] = result;
model.trigger('resultsIn', result);
}
function errorFunction (xhr, status, strErr) {
// Currently does not inform user of failure of form submission
// console.log("fail");
}
return model;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment