Jump to content

[SOLVED] AJAX Suggest Problem -- Properly Emptying Suggestions


Recommended Posts

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>

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" />

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

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?

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

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

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

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

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.

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

 

 

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.

  • 3 weeks later...

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

 

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.