kjtocool Posted August 25, 2008 Share Posted August 25, 2008 Hi all, I am trying to build a custom AJAX suggestion text box, the idea being that as a user types, the box will query a database and return matching results. I am running into an issue, basically, the suggestions get populated properly, but when the box is showing results and the user clicks away from the search box, the suggestions remain! I can't find a feasible way to remove them. I have tried a onblur="removeSuggestions()" call on the textbox. The call will work fine, but onblur executes before the onclick event in the div that holds the suggestions. So, it gets rid of the suggestions and discounts the users click, since it caused the text box to lose focus, and that event fires first. I am very new to AJAX, and this if my first real go at it, so I'm sure this is a silly problem. Any help would be appreciated. Example of the box not going away (no onblur event in this example, so the suggestions just stay): Link JS Code var xmlHttp; /** * Called initially * ## Calls GetXmlHttpObject() * ## Calls stateChanged() * -- Creates and sends the xmlHttp object * * @param {String} userInput the input the user types in the search box */ function suggest(userInput) { if (userInput.length == 0) { document.getElementById("suggestions").innerHTML = ""; return; } xmlHttp = GetXmlHttpObject(); if (xmlHttp == null) { alert("Your browser does not support this application. Please update to a newer version."); return; } var url = "database.php?query=" + userInput + "&sid=" + Math.random(); xmlHttp.onreadystatechange = stateChanged; xmlHttp.open("GET", url, true); xmlHttp.send(null); } /** * Called by stateChanged() * ## Calls trim() * -- Handles the onclick event for when a suggestion is clicked * * @param {Object} userInput the input the user types in the search box */ function correct(userInput) { document.getElementById("inputtext").value = trim(userInput); document.getElementById("suggestions").style.display = 'none'; // Removing the suggestions? } /** * Called when text box loses focus (currently not used) * -- Clears the suggestion div */ function lostFocus() { document.getElementById("suggestions").innerHTML = ""; } /** * Called by suggest() * -- Handles a change in the state of xmlHttp object * -- Splits all returned results on "," and returns them in an UL */ function stateChanged() { if (xmlHttp.readyState == 4 || xmlHttp.readyState == "complete") { var split = xmlHttp.responseText.split(","); var suggestionList = ""; if(split[0] != "") { for(var i = 0; i < split.length; i++) { suggestionList += "<li><a href=\"#\" onclick=\"javascript: correct('" + split[i] + "');\"> " + split[i] + "</a></li>"; } if(suggestionList != "") { suggestionList = "<ul>" + suggestionList; suggestionList += "</ul>"; } } document.getElementById("suggestions").innerHTML = suggestionList; document.getElementById("suggestions").style.display = 'block'; } } /** * Called by suggest() * -- Creates and returns the xmlHttp object */ function GetXmlHttpObject() { var xmlHttp = null; try { xmlHttp = new XMLHttpRequest(); // Firefox, Opera 8.0+, Safari } catch (e) { try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); // Internet Explorer } catch (e) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // Internet Explorer } } return xmlHttp; } /** * Called by stateChanged() * -- Trims the whitespace from a string * * @param {String} str the string to trim */ function trim(str) { if (str != null) { var i; for (i = 0; i < str.length; i++) { if (str.charAt(i) != " ") { str = str.substring(i, str.length); break; } } for (i = str.length - 1; i >= 0; i--) { if (str.charAt(i)!= " ") { str = str.substring(0, i + 1); break; } } if (str.charAt(0) == " ") { return ""; } else { return str; } } return null; } HTML Code <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="suggest.js"> </script> <script type="text/javascript"> function test() { alert("test") } </script> <link rel="stylesheet" type="text/css" href="style.css" /> <!--[if IE]> <link rel="stylesheet" type="text/css" href="ie.css" /> <![endif]--> <title>Auto Suggest Example</title> </head> <body> <form action="#" method="post" > <table border="0" cellpadding="0" cellspacing="0" align="center" style="width: 80%"> <tr> <td> <input type="text" id="inputtext" onkeyup="suggest(this.value)" autocomplete="off" class="style1" /> <input type="submit" name="submit" value="Search" class="style1" /> <br /> <div id="suggestions" style="display: block"> </div> </td> </tr> <tr> <td height="25" class="style1"> Version 1.0.24 </td> </tr> </table> </form> </body> </html> Quote Link to comment Share on other sites More sharing options...
Ken2k7 Posted August 25, 2008 Share Posted August 25, 2008 Change this: <input type="text" id="inputtext" onkeyup="suggest(this.value)" autocomplete="off" class="style1" /> To: <input type="text" id="inputtext" onkeyup="suggest(this.value)" onblur='lostFocus();' autocomplete="off" class="style1" /> Quote Link to comment Share on other sites More sharing options...
kjtocool Posted August 25, 2008 Author Share Posted August 25, 2008 I've tried that. If I do that, as described above, you then can't select one of the 'suggestions.' This happens because the onblur event fires before the onclick event of the suggestion, which then sets the div to "", clearing the suggestions and forgetting about the users click! I've added an example of what happens with that code, you can find it here: Link Quote Link to comment Share on other sites More sharing options...
Ken2k7 Posted August 26, 2008 Share Posted August 26, 2008 You can modify the lostFocus() function to not execute if the focus is on the suggestions, right? Quote Link to comment Share on other sites More sharing options...
kjtocool Posted August 26, 2008 Author Share Posted August 26, 2008 Well, it makes sense in my head ... but I've never done that before. How would you go about it? /** * Called when text box loses focus (currently not used) * -- Clears the suggestion div */ function lostFocus() { if(document.getElementById("suggestions").????) { document.getElementById("suggestions").innerHTML = ""; } } I just don't know how to find out if the div has focus / has been clicked. The only way I can think of is to have each div have an onfocus() and onblur() function, which would then set a variable which you could then test in the lostFocus() function ... like so: isFocused=false; elem.onfocus=function(){isFocused=true} elem.onblur=function(){isFocused=false} What worries me then is that, since both the div and textbox could theoretically have focus, if I clicked out of both while they both had focus ... which onblur() function would fire first? Quote Link to comment Share on other sites More sharing options...
Zane Posted August 26, 2008 Share Posted August 26, 2008 see if you can't attach the onblur to the div instead of the textbox that's the reason the onblur fires first, when you click on the div...you're loosing focus of the textbox probably depends on the browser support if it works or not...and if it doesn't I'm sure there's a way around it EDIT: yeah I tested it with FireBug and that works just fine Quote Link to comment Share on other sites More sharing options...
kjtocool Posted August 26, 2008 Author Share Posted August 26, 2008 Zanus, I just tested it in both IE and Firefox, putting the onblur="lostFocus()" on the div doesn't work. The div never notices a loss of focus, and just remains open exactly like the first example. Example of this attempt: Link Quote Link to comment Share on other sites More sharing options...
Zane Posted August 26, 2008 Share Posted August 26, 2008 It works just fine for me, not saying it does for you There's obviously a setting wrong on your end, but when I click tiger or what not it plops the word into the textbox like I'd imagine you programmed it to do EDIT: oh nevermind I lost focus of the actual problem...lol still doesn't work Quote Link to comment Share on other sites More sharing options...
kjtocool Posted August 26, 2008 Author Share Posted August 26, 2008 Heh, Yeah, it plops the word in just fine, it's just if you click elsewhere on the page, and want the suggestions to disappear, they stay there until you click one! Quote Link to comment Share on other sites More sharing options...
Zane Posted August 26, 2008 Share Posted August 26, 2008 maybe the Div doesn't have focus in the first place....... perhaps you could put an alert to tell if it has focus or not since of course onblur only works when div looses focus Edit: hell, maybe you just add the focus() function to the AJAX part of it all.....force focus on it and see if onblur works Quote Link to comment Share on other sites More sharing options...
kjtocool Posted August 26, 2008 Author Share Posted August 26, 2008 it clearly doesn't have focus. I will play with it more tomorrow, at least now I have a few ideas to go with. Quote Link to comment Share on other sites More sharing options...
Ken2k7 Posted August 26, 2008 Share Posted August 26, 2008 Don't bother, I don't think you can't get focus on anything other than the supported objects listed here. So a <DIV> with plain text won't work because you can never focus on it. You can use the setTimeout() function to delay the process so it shows for `t` milliseconds before going away. If you set it correctly, it shouldn't be too much of a problem. If it goes away, just type something and it'll come back. Quote Link to comment Share on other sites More sharing options...
Zane Posted August 26, 2008 Share Posted August 26, 2008 here's some good information http://www.webmasterworld.com/forum91/5303.htm Check around for body.onClick and using event.target I'm interested to see how it all comes together....I hardly ever get to see a barebones simply laid out AJAX suggest example. I play around with this stuff a lot too. You can use the setTimeout() function to delay the process so it shows for `t` milliseconds before going away. If you set it correctly, it shouldn't be too much of a problem. If it goes away, just type something and it'll come back. That seems a little bit of an afro-enginieering thing if you ask me...would probably work like a charm though Quote Link to comment Share on other sites More sharing options...
kjtocool Posted August 26, 2008 Author Share Posted August 26, 2008 Yep, thanks guys for your help. The solution was with the flags I mentioned above, and mentioned in the thread zanus linked too. What I did was put an onclick="testFocus();" event on the BODY tag. Thankfully, this fires AFTER the onclick="correct()" function of each LI in the suggestion box. Because it fires after, what I was able to do was: Anytime the xmlHttp object hits readyState 4, I turn a suggestionsShown variable to true. Anytime the correct() function is called, which happens if the user clicks a suggestion, I set the variable back to false. Thus, since the body onclick fires second, if the flag is true, the testFocus() function simply empties the suggestions, and walla, it all works perfectly. There are a few minor tweaks to make yet, I want to handle the mouseup, mousedown events, throttle the function for fast typers, as well as a few other small issues. I'll be sure to post my code on completion. Quote Link to comment Share on other sites More sharing options...
kjtocool Posted September 12, 2008 Author Share Posted September 12, 2008 Whew! It took a while, but I finished all the enhancements and upgrades. What's left is a very simple, streamlined AJAX Suggest example which mimics the functionality of Google Suggest. The only thing it doesn't do is auto submit when a user selects a suggestion, that will get added in the near future. Regardless, I handled all the events: arrow up key, arrow down key, tab, etc ... the whole 9 yards. I figured I would write a tutorial on the process since it was all such a learning experience, it includes a link to download all the files if you're so inclined. http://www.xtinctdesigns.com/tutorials.php Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.