I have a few other suggestions on how this could be even "better", but after looking it over, it appears another answer here gives some of those suggestions. However, if you'd like me to rewrite the below code using said suggestions, lemme know and I'll update the code.
The suggestions are simple little things like keeping all CSS in one place and discontinuing the hover functions for CSS :hover
. As I noted in my comments, I left some of this as was to stay "close" to the train of thought you appeared to be on with your code. While I did introduce some different concepts, I'm hoping the basic flow I tried to stay with will make it easier for you to read through the comments there and see how all these wonderful parts work together!
I would suggest some of the following || this is how I might do it and why:
ExAmPlE
// My own namespace for any global assignments, thus lowering chance of error of conflict with other code var mySearch = { ajaxSearch: undefined, // variable for use with getJSON. useful if you want to stop the ajax call current: undefined, // variable for keeping up with current search term // this should also meet your requirements for "cache search" // Method for preforming search, the passing parameter should be the event variable from the action triggering the search gitSearch: function(e) { // i don't quite understand not touching the HTML as the input has no name, thus it can't post correctly to server, // tho I see in your example, you simply add the input value to the request url after a "/", // thus I assume the server has a rewrite method for proccessing. var query = $(this).val(); // because of how we call this method, we can simply use "$(this)" to get the input, since this IS the input if (mySearch.current == query) return; // ensure we're not preforming same search just performed, possibly less than second ago due to multiple ways of calling // no need to continue, we just did this work mySearch.current = query; // reset current search value if (!query) alert("Please enter a term to search for"); else { $('#results').html('Searching...'); // sets content of results area to show it's doing something $.getJSON(mySearch.requestBaseUrl + query) .done(function(json) { if (json['repositories']) { if (json.repositories.length) { // works if return is array (it is) and determines if ANY results were returned // clear results from previous search and add our new <ul> $('#results').empty().append($('<ul />')); $.each(json.repositories, function(i, v) { // variable "v" is same as json.repositories[i] var txt = v.owner + " / " + v.name, css = 'cursor: pointer; list-style-type: none; width: 500px;', sb = [ // literal array for creating each Line of text "Repo Lanuage is : " + v.language, "There are " + v.followers + " followers of this repo.", "The URL of the repo is : " + v.url, "The description of the repo : " + v.description ], msg = sb.join('\n'); // this joins our "string builder"/"literal array" into ONE string using "\n" between each "line" (item in array) // easy syntax to make new element using jQuery $('<li />', { text: txt, style: css }) .attr('title', 'Created: ' + new Date(v.created)) .data('msgAlert', msg) // assign msg for alert to this elements data for recall .appendTo($('#results ul')); }); } else $('#results').html($('<h2 />', { text: 'No results found.' })); } else alert('Could not find any values.'); }) .fail(function(status){ $('#results').html('ERROR: Please see console.'); console.log(status); }); } }, requestBaseUrl: 'https://api.github.com/legacy/repos/search/', tmrSearch: undefined // this will be used for my "stopped typing" search }; $(function() { // same as doc.onready / (function(window)) keeps the window variable closer at hand, but i see no reason for it's use here // add your page styling. $('<style />', { html: 'body { background-image:url(http://n2.9cloud.us/766/a_beautiful_large_scale_shot_for_th_100120255.jpg); font-size:20px; font-family:"Arial, Helvetica", sans-serif; }' }).appendTo("head"); // since we changed to onready, we can just alert the info, unless you want it to wait a second alert("Please type the term to search GitHub for in the text field and hit the ENTER key."); // also, for future reference, when you use setTimeout with a function as you did, you can shortent he call to simply: // setTimeout(alertInstructions, 1000); // As for the calls to begin search, I will go 3 avenues. // First I will include using "Enter" key, but only on input focus // I will also want to preform search on input blur and after user stops typing for a second (like a google quick search) // // I, personally like to delegate my events to $(document), as this makes them readily available for dynamic elements, // however, this can be bad practice. If you attach to many events to the DOM as such, you can end up with overhead that // could crash your program. Since your base example gives us ID's of static elements, I will use those, but I suggest you // read jQuery docs about delegating events. Newer jQuery, as you're using, uses .on -> http://api.jquery.com/on/ $('#search') // the following structure is called "chaining". jQuery provides us this nice way to make multiple calls to one element without recalling that element .on('blur', mySearch.gitSearch) // this is all that's needed to register this method to this event // blur is when input loses focus (click on something else) .on('keypress', function(e) { // this will apply the Method as if it was the base function of this event // .apply is JS way to trigger a method and send, as params, what to use as "this" and what arguments to feed // note, arguments must be as an array. Doing [e], wraps our Event Argument passed from "keypress" onto the parameter of our method if (e.which == 13) mySearch.gitSearch.apply(this, [e]); }) // the following is one easy way to determine when user stops typing and begin search. // The proccess is simple. Simply clear a timer on keydown, then reset it on keyup. When the timer reaches its end, it preforms the search! .on('keydown', function(e) { clearTimeout(mySearch.tmrSearch); }) .on('keyup', function(e) { var $this = this; // needed to pass "this" variable on Timeout mySearch.tmrSearch = setTimeout(function() { mySearch.gitSearch.apply($this, [e]); }, 2000); // sets to 2 seconds. // if not cleared by keydown within the given time, then "gitSearch" will be preformed! }) // in finally doing the "gitSearch" method, I noticed you do have a need for delegating events, thus I will delegate those events here // by doing this here, and assinging to document, we don't have to keep rebuilding those event methods everytime you get new search results. // Keep in mind, many, including jQuery recomend using a parent node. However, years of experience with this have taught me, it's not really neccessary // unless you're delegating A LOT of events to the Document. If you have a larger application, find static parents to delegate events too! // Also, I personally am not a big fan of hover. I've had problems in the past with upgrading jQuery and finding unexpected changes on hover methods, // thus I go back to good old mouse-movements $(document) .on('mouseenter', '#results li', function(e) { $(this).css({'color':'#ffffff'}); }) .on('mouseleave', '#results li', function(e) { $(this).css({'color':'#000000'}); }) .on('click', '#results li', function(e) { var msg = $(this).data('msgAlert'); if (msg) alert(msg); alert(msg); // joins our "string builder", literal array into ONE string using "/n" between each "line" (item in array) }); })
ExAmPlE