Wrox Programmer Forums
Go Back   Wrox Programmer Forums > Web Programming > JavaScript > Javascript
|
Javascript General Javascript discussions.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the Javascript section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old October 22nd, 2008, 07:52 AM
Registered User
 
Join Date: Jul 2008
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default AutoSuggest typeAhead issue

Hi All,

 I am try to use Nicholas C. Zakas's auto suggest control.
But there is issue with this. I tried to resolve but didn't get success.
Problem is that

When I start type the word automatically completed by undesired word.
It doesn't wait for next character.

For example

If I start typing ma it completes with maine without waiting for the next character.

I want to text box value should not fill until unless pressing enter key.

Please Help.


Thanks In Advance.


Regards,
Dinesh

 
Old October 22nd, 2008, 01:48 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

Might help if you told people where to find Mr. Zakas's control. I, for one, have never heard of it. Or show code, even better.
 
Old October 23rd, 2008, 02:15 AM
Registered User
 
Join Date: Jul 2008
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Here is the code

example.html

<html>
    <head>
        <title>Autosuggest Example</title>
        <script type="text/javascript" src="json.js"></script>
        <script type="text/javascript" src="zxml.js"></script>
        <script type="text/javascript" src="autosuggest.js"></script>
        <link rel="stylesheet" type="text/css" href="autosuggest.css" />
        <script type="text/javascript">
            window.onload = function () {
                var oTextbox = new AutoSuggestControl(document.getElementById("txtSta te"), new SuggestionProvider());
            }
        </script>
    </head>
    <body>
        <form method="get" onsubmit="alert('Submitted!')">
            <table border="0">
                <tr>
                    <td>Name:</td>
                    <td><input type="text" name="txtName" id="txtName" /></td>
                </tr>

                <tr>
                    <td>State/Province:</td>
                    <td><input type="text" name="txtState" id="txtState" autocomplete="off"/></td>
                </tr>

                <tr>
                    <td>Country:</td>
                    <td><select name="country" id="country"><option value="IN">India</option></select></td>
                </tr>
            </table>
        </form>
    </body>
</html>



autosuggest.js


/**
 * An autosuggest textbox control.
 * @class
 * @scope public
 */
function AutoSuggestControl(oTextbox /*:HTMLInputElement*/,
                            oProvider /*:SuggestionProvider*/) {

    /**
     * The currently selected suggestions.
     * @scope private
     */
    this.cur /*:int*/ = -1;

    /**
     * The dropdown list layer.
     * @scope private
     */
    this.layer = null;

    /**
     * Suggestion provider for the autosuggest feature.
     * @scope private.
     */
    this.provider /*:SuggestionProvider*/ = oProvider;

    /**
     * The textbox to capture.
     * @scope private
     */
    this.textbox /*:HTMLInputElement*/ = oTextbox;

    /**
     * Timeout ID for fast typers.
     * @scope private
     */
    this.timeoutId /*:int*/ = null;

    /**
     * The text that the user typed.
     * @scope private
     */
    this.userText /*:String*/ = oTextbox.value;

    //initialize the control
    this.init();

}

/**
 * Autosuggests one or more suggestions for what the user has typed.
 * If no suggestions are passed in, then no autosuggest occurs.
 * @scope private
 * @param aSuggestions An array of suggestion strings.
 * @param bTypeAhead If the control should provide a type ahead suggestion.
 */
AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/,
                                                     bTypeAhead /*:boolean*/) {

    //re-initialize pointer to current suggestion
    this.cur = -1;

    //make sure there's at least one suggestion
    if (aSuggestions.length > 0) {
        this.showSuggestions(aSuggestions);
        if (bTypeAhead)
           this.typeAhead(aSuggestions[0]);

    } else {
        this.hideSuggestions();
    }
};

/**
 * Creates the dropdown layer to display multiple suggestions.
 * @scope private
 */
AutoSuggestControl.prototype.createDropDown = function () {


    //create the layer and assign styles
    this.layer = document.createElement("div");
    this.id="suggestDiv";
    this.layer.className = "suggestions";
    this.layer.style.visibility = "hidden";
    this.layer.style.width = this.textbox.offsetWidth;
    document.body.appendChild(this.layer);

    //when the user clicks on the a suggestion, get the text (innerHTML)
    //and place it into a textbox
    var oThis = this;
    this.layer.onmousedown =
    this.layer.onmouseup =
    this.layer.onmouseover = function (oEvent) {
        oEvent = oEvent || window.event;
        oTarget = oEvent.target || oEvent.srcElement;

        if (oEvent.type == "mousedown") {
            oThis.textbox.value = oTarget.firstChild.nodeValue;
            oThis.hideSuggestions();
        } else if (oEvent.type == "mouseover") {
            oThis.highlightSuggestion(oTarget);
        } else {
            oThis.textbox.focus();
            oThis.textbox.value = oThis.textbox.value;
        }
    };

};

/**
 * Gets the left coordinate of the textbox.
 * @scope private
 * @return The left coordinate of the textbox in pixels.
 */
AutoSuggestControl.prototype.getLeft = function () /*:int*/ {

    var oNode = this.textbox;
    var iLeft = 0;

    while(oNode.tagName != "BODY") {
        iLeft += oNode.offsetLeft;
        oNode = oNode.offsetParent;
    }

    return iLeft;
};

/**
 * Gets the top coordinate of the textbox.
 * @scope private
 * @return The top coordinate of the textbox in pixels.
 */
AutoSuggestControl.prototype.getTop = function () /*:int*/ {

    var oNode = this.textbox;
    var iTop = 0;

    while(oNode.tagName != "BODY") {
        iTop += oNode.offsetTop;
        oNode = oNode.offsetParent;
    }

    return iTop;
};

/**
 * Highlights the next or previous suggestion in the dropdown and
 * places the suggestion into the textbox.
 * @param iDiff Either a positive or negative number indicating whether
 * to select the next or previous sugggestion, respectively.
 * @scope private
 */
AutoSuggestControl.prototype.goToSuggestion = function (iDiff /*:int*/) {
    var cSuggestionNodes = this.layer.childNodes;

    if (cSuggestionNodes.length > 0) {
        var oNode = null;

        if (iDiff > 0) {
            if (this.cur < cSuggestionNodes.length-1)
                oNode = cSuggestionNodes[++this.cur];
        } else if (this.cur > 0) {

                oNode = cSuggestionNodes[--this.cur];
        }

        if (oNode) {
            this.highlightSuggestion(oNode);
            this.textbox.value = oNode.firstChild.nodeValue;
        }
    }
};

/**
 * Handles three keydown events.
 * @scope private
 * @param oEvent The event object for the keydown event.
 */
AutoSuggestControl.prototype.handleKeyDown = function (oEvent /*:Event*/) {

    switch(oEvent.keyCode) {
        case 38: //up arrow
            this.goToSuggestion(-1);
            break;
        case 40: //down arrow
            this.goToSuggestion(1);
            break;
        case 27: //esc
            this.textbox.value = this.userText;
            this.selectRange(this.userText.length, 0);
            //break;
            /* falls through */
        case 13: //enter
            this.hideSuggestions();
            oEvent.returnValue = false;
            if (oEvent.preventDefault) {
                oEvent.preventDefault();
            }
            break;
    }

};

/**
 * Handles keyup events.
 * @scope private
 * @param oEvent The event object for the keyup event.
 */
AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) {

    var iKeyCode = oEvent.keyCode;
    var oThis = this;

    //get the currently entered text
    this.userText = this.textbox.value;

    clearTimeout(this.timeoutId);

    //for backspace (8) and delete (46), shows suggestions without typeahead
    if (iKeyCode == 8 || iKeyCode == 46) {

        this.timeoutId = setTimeout( function () {
            oThis.provider.requestSuggestions(oThis, false);
        }, 250);

    //make sure not to interfere with non-character keys
    } else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123)) {
        //ignore
    } else {
        //request suggestions from the suggestion provider with typeahead
        this.timeoutId = setTimeout( function () {
            oThis.provider.requestSuggestions(oThis, true);
        }, 250);
    }
};

/**
 * Hides the suggestion dropdown.
 * @scope private
 */
AutoSuggestControl.prototype.hideSuggestions = function () {
    this.layer.style.visibility = "hidden";
    var el=document.getElementById('suggIFrame')
    if(el != null && el != 'undefined'){
        var arr = new Array(el);
        if(arr.length > 0){arr[0].parentNode.removeChild(arr[0]);}
    }
};

/**
 * Highlights the given node in the suggestions dropdown.
 * @scope private
 * @param oSuggestionNode The node representing a suggestion in the dropdown.
 */
AutoSuggestControl.prototype.highlightSuggestion = function (oSuggestionNode) {

    for (var i=0; i < this.layer.childNodes.length; i++) {
        var oNode = this.layer.childNodes[i];
        if (oNode == oSuggestionNode) {
            oNode.className = "current"
        } else if (oNode.className == "current") {
            oNode.className = "";
        }
    }
};

/**
 * Initializes the textbox with event handlers for
 * auto suggest functionality.
 * @scope private
 */
AutoSuggestControl.prototype.init = function () {

    //save a reference to this object
    var oThis = this;

    //assign the onkeyup event handler
    this.textbox.onkeyup = function (oEvent) {

        //check for the proper location of the event object
        if (!oEvent) {
            oEvent = window.event;
        }

        //call the handleKeyUp() method with the event object
        oThis.handleKeyUp(oEvent);
    };

    //assign onkeydown event handler
    this.textbox.onkeydown = function (oEvent) {

        //check for the proper location of the event object
        if (!oEvent) {
            oEvent = window.event;
        }

        //call the handleKeyDown() method with the event object
        oThis.handleKeyDown(oEvent);
    };

    //assign onblur event handler (hides suggestions)
    this.textbox.onblur = function () {
        oThis.hideSuggestions();
    };

    //create the suggestions dropdown
    this.createDropDown();
};

/**
 * Selects a range of text in the textbox.
 * @scope public
 * @param iStart The start index (base 0) of the selection.
 * @param iEnd The end index of the selection.
 */
AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iEnd /*:int*/) {

    //use text ranges for Internet Explorer
    if (this.textbox.createTextRange) {
        var oRange = this.textbox.createTextRange();
        oRange.moveStart("character", iStart);
        oRange.moveEnd("character", iEnd - this.textbox.value.length);
        oRange.select();
    //use setSelectionRange() for Mozilla
    } else if (this.textbox.setSelectionRange) {
        this.textbox.setSelectionRange(iStart, iEnd);
    }

    //set focus back to the textbox
    this.textbox.focus();

};
AutoSuggestControl.prototype.selectRange1 = function(oText, oSuggest){
        var oLen = oText.value.length;
        var nIdx = oSuggest.toLowerCase().indexOf( oText.value, 0 )
        if( nIdx == 0 && oSuggest.length > oText.value.length )
        {
            oText.value = oSuggest;
            if( oText.createTextRange )
            {
                hRange = oText.createTextRange();
                hRange.findText( oSuggest.substr( oLen ) );
                hRange.select()
            }
            else
            {
                oText.setSelectionRange( oLen, oSuggest.length );
            }
        }
};
/**
 * Inserts a suggestion into the textbox, highlighting the
 * suggested part of the text.
 * @scope private
 * @param sSuggestion The suggestion for the textbox.
 */
AutoSuggestControl.prototype.typeAhead = function (sSuggestion /*:String*/) {

    //check for support of typeahead functionality
    if (this.textbox.createTextRange || this.textbox.setSelectionRange){
        var iLen = this.textbox.value.length;
        this.textbox.value = sSuggestion;
        this.selectRange(iLen, sSuggestion.length);
        //this.selectRange1(this.textbox,sSuggestion)
    }
};

/**
 * Builds the suggestion layer contents, moves it into position,
 * and displays the layer.
 * @scope private
 * @param aSuggestions An array of suggestions for the control.
 */
AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/) {

    var oDiv = null;
    this.layer.innerHTML = ""; //clear contents of the layer

    for (var i=0; i < aSuggestions.length; i++) {
        oDiv = document.createElement("div");
        oDiv.appendChild(document.createTextNode(aSuggesti ons[i]));
        this.layer.appendChild(oDiv);
    }

    this.layer.style.left = this.getLeft() + "px";
    this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
    this.layer.style.visibility = "visible";

    if(navigator.appName == "Microsoft Internet Explorer")
    {
        var divNode = this.layer;

        divNode.insertAdjacentHTML("afterEnd", '<IFRAME frameBorder="0" scrolling="no" id="suggIFrame" name="suggIFrame"style="position:absolute; z-index:5; filter:progid:DXImageTransform.Microsoft.Alpha(opa city=0); " />');
        var iframeShim = document.getElementById("suggIFrame");
        iframeShim.style.top = divNode.style.top;
        iframeShim.style.left = divNode.style.left
        iframeShim.style.width = divNode.offsetWidth;
        iframeShim.style.height = divNode.offsetHeight;
    }

};

/**
 * Provides suggestions for state/province names.
 * @class
 * @scope public
 */
function SuggestionProvider() {
    this.http = zXmlHttp.createRequest();
}

/**
 * Request suggestions for the given autosuggest control.
 * @scope protected
 * @param oAutoSuggestControl The autosuggest control to provide suggestions for.
 */
SuggestionProvider.prototype.requestSuggestions = function (oAutoSuggestControl /*:AutoSuggestControl*/,
                                                            bTypeAhead /*:boolean*/) {

    var oHttp = this.http;

    //cancel any active requests
    if (oHttp.readyState != 0) {
        oHttp.abort();
    }

    //define the data
    var oData = {
        requesting: "StatesAndProvinces",
        text: oAutoSuggestControl.userText,
        limit: 5
    };

    //open connection to server
    oHttp.open("post", "suggestions.php", true);
    oHttp.onreadystatechange = function () {
        if (oHttp.readyState == 4) {
            //evaluate the returned text JavaScript (an array)
            var aSuggestions = JSON.parse(oHttp.responseText);

            //provide suggestions to the control
            oAutoSuggestControl.autosuggest(aSuggestions, bTypeAhead);
        }
    };

    //send the request
    oHttp.send(JSON.stringify(oData));

};

http://www.nczonline.net/downloads/

 
Old October 23rd, 2008, 05:50 AM
joefawcett's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 3,074
Thanks: 1
Thanked 38 Times in 37 Posts
Default

Well I'm not sure I understand, what's the point of an autosuggest if it doesn't suggest? It only fills in the full word if no other words could complete the characters typed so far.

--

Joe (Microsoft MVP - XML)
 
Old October 23rd, 2008, 04:57 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

It's fascinating, how much code this approach takes to do something that should be so simple. Almost amazing. I'll bet I could write it in a quarter of the code.
 
Old October 24th, 2008, 03:38 AM
joefawcett's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 3,074
Thanks: 1
Thanked 38 Times in 37 Posts
Default

You're on. I've written one myself and it was of comparable length. If you do it in less than half I'll be surprised, you may find it's not as simple as you think.

--

Joe (Microsoft MVP - XML)
 
Old October 24th, 2008, 04:29 AM
Authorized User
 
Join Date: Sep 2008
Posts: 87
Thanks: 1
Thanked 0 Times in 0 Posts
Default

are u expecting for say if we type
M the text box should show a dropdown containing the states names which starts with M ........



 
Old October 24th, 2008, 05:20 AM
Registered User
 
Join Date: Jul 2008
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi,

I just want to text should not be be text box as value until unless I select , should not be selected automatically.

I want to implement type-ahead functionality.

If any body have reference site or example please let me know.

I have taken the code from here
http://www.nczonline.net/downloads/

Thanks


 
Old October 24th, 2008, 03:00 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

Okay, Joe, here you go.

It's not very pretty; needs work on the CSS. And I probably shouldn't just use the <IFRAME> to do the display, because MSIE has a ridiculously large minimum size for an IFRAME and FireFox has other oddities. If you care a lot, I'll fix that. Wouldn't be more than another few lines.

***** completionDemo.html *****
Code:
<html>
<head>
<style>
div#HOLDER { position: absolute; top: 0px; left: 0px; 
             display: none;
           }
iframe#MATCHER { width: 225px; height: 100px; }
input.WORD { width: 225px; 
             font-family: verdana, arial; font-size: small; 
           }
</style>

<script language=javascript>
var matchField = null;

function showMatch( toWhat )
{
    var tLeft = 0, tTop = 0;
    var node = toWhat;
    while ( node != null )
    {
        tTop  += node.offsetTop;
        tLeft += node.offsetLeft;
        node = node.offsetParent;
    }
    var dv = document.getElementById("HOLDER");
    dv.style.top = ( tTop + 20 ) + "px";
    dv.style.left = tLeft + "px";

    document.getElementById("MATCHER").src = "usstates.asp?word=" + toWhat.value;
    matchField = toWhat;
}

function showMatches( )
{
    document.getElementById("HOLDER").style.display = "block";
}
function hideMatches( )
{
    document.getElementById("HOLDER").style.display = "none";
}
function copyMatch( from )
{
    matchField.value = from.innerHTML.replace(/\&nbsp\;/g," ");
    setTimeout("hideMatches()",200);
}
</script>
</head>
<body>
<div id="HOLDER">
<iframe id="MATCHER"></iframe>
</div>

<form>
Enter the state where you were born:
<input class="WORD" name="born" size="20" onkeyup="showMatch(this);" />
<p>
And then enter the state where you are living now:
<input class="WORD" name="residence" size="20" onkeyup="showMatch(this);" />
</form>
</body>
</html>
**********************************************

This is a silly little ASP page that just uses an array, instead of a DB query, so that I could post all the code here. The number of lines in the array and the linear array search are surely more lines thatn would be needed to do a simple DB query.

******* file: USStates.asp *******
Code:
<html>
<head>
<style>
body { background-color: lightyellow; 
       border: solid brown 2px;
       padding: 5px;
     }
a { text-decoration: none; 
    font-family: verdana, arial; font-size: small; 
    color: brown;
  }
</style>
</head>
<body onclick="parent.hideMatches();">
<%
USStates = Array( "ALABAMA", "ALASKA", "AMERICAN&nbsp;SAMOA", "ARIZONA", "ARKANSAS", _
    "CALIFORNIA", "COLORADO", "CONNECTICUT", "DELAWARE", "DISTRICT&nbsp;OF&nbsp;COLUMBIA", _
    "FEDERATED STATES&nbsp;OF&nbsp;MICRONESIA", "FLORIDA", "GEORGIA", "GUAM", _
    "HAWAII", "IDAHO", "ILLINOIS", "INDIANA", "IOWA", "KANSAS", "KENTUCKY", _
    "LOUISIANA", "MAINE", "MARSHALL ISLANDS", "MARYLAND", "MASSACHUSETTS", _
    "MICHIGAN", "MINNESOTA", "MISSISSIPPI", "MISSOURI", "MONTANA", "NEBRASKA", _
    "NEVADA", "NEW&nbsp;HAMPSHIRE", "NEW&nbsp;JERSEY", "NEW&nbsp;MEXICO", _
    "NEW&nbsp;YORK", "NORTH&nbsp;CAROLINA", "NORTH&nbsp;DAKOTA", "NORTHERN&nbsp;MARIANA&nbsp;ISLANDS", _
    "OHIO", "OKLAHOMA", "OREGON", "PALAU", "PENNSYLVANIA", "PUERTO&nbsp;RICO", _
    "RHODE&nbsp;ISLAND", "SOUTH&nbsp;CAROLINA", "SOUTH&nbsp;DAKOTA", "TENNESSEE", _
    "TEXAS", "UTAH", "VERMONT", "VIRGIN&nbsp;ISLANDS", "VIRGINIA", _
    "WASHINGTON", "WEST&nbsp;VIRGINIA", "WISCONSIN", "WYOMING" _
    )

word = UCASE( Trim("" & Request("word")) )
wlen = Len(word)
found = 0
If wlen > 0 Then
    For s = 0 To UBound(USStates)
        st = USStates(s)
        If Left(st,wlen) = word Then
            found = found + 1
%><a ID="WORD" href="#" onclick="parent.copyMatch(this);"><%=st%></a><br />
<%
        End If
    Next
End If
%></body>
<%
If found > 1 Then 
%>
<script>
// show all matches
parent.showMatches();
</script>
<% Elseif found = 1 Then %>
<script>
// purposely delay a bit to show we are picking the only match
setTimeout( "parent.copyMatch(document.getElementById('WORD'))", 750 );
</script>
<% Else %>
<script>
// no matches, no display
parent.hideMatches();
</script>
<% End If %>
</html>
***********************************

Occurs to me I could easily do many types of completion (e.g., US States, countries, etc.) by just passing another argument to what is here the "USStates.asp" page that specifies what table to search.
 
Old October 24th, 2008, 04:38 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

Here...got rid of the visible <IFRAME>. Made it much prettier.

http://www.clearviewdesign.com/Newbi...etionDemo.html

Also introduced a delay between time we discover there is only one matching selection and time that it is "auto-chosen" so the user can keep typing and override the automatic selection. I think that's what original poster was asking for.

You can just do VIEW==>>SOURCE to see the HTML page.

And then I also uploaded
http://www.clearviewdesign.com/Newbi.../USStates.html
as a viewable form of the ASP page that is invoked.





Similar Threads
Thread Thread Starter Forum Replies Last Post
autosuggest using ajax rajesh_css Ajax 1 October 29th, 2008 03:09 AM
Ch.7 - Autosuggest example - some modifications ice84 BOOK: Professional Ajax ISBN: 978-0-471-77778-6 10 September 17th, 2007 05:37 AM
AutoSuggest and Links gt96 BOOK: Professional Ajax ISBN: 978-0-471-77778-6 1 July 4th, 2006 04:58 PM
Extend Autosuggest control [email protected] BOOK: Professional Ajax ISBN: 978-0-471-77778-6 0 May 27th, 2006 03:08 AM
Autosuggest Textbox Issue smay Javascript 3 August 3rd, 2005 02:25 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.