Making autosuggest top layer

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Claus Mygind
    Contributor
    • Mar 2008
    • 571

    #1

    Making autosuggest top layer

    I am adding autosuggest to my code. My problem is the autosuggest response appears behind my other <div>'s and when I try to assign a higher z-index I get a "invalid assignment left-hand side" error.

    Here is the section of code that is giving me trouble. The entire context is at the bottom of this post in the section title "autosugges t code" where I have also highlighted the code.
    Code:
        this.layer.style.left = this.getLeft() + "px";
        this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
    	this.layer.style.position = "absolute";
    	[B][U]this.layer.style.z-index = 200;[/U][/B]
        this.layer.style.visibility = "visible";
    
    };


    Here is the relevant code (I hope)
    CSS
    Code:
    #fullWidth {
    	position: absolute;
    	white-space: nowrap; 
    	left: 0%; 
    	top: 25px;
    	width: 99%;
    	color: #333333;
    	padding:5px;
    	font-size: 10pt;
    	overflow: hidden;
    	z-index: 98;
    }
    .subHeading3 {
      color: black;
      font-size: 12pt;
      font-weight: 900;
    }
    HTML
    Code:
    <body id="coverPage" onload="myStartUp();">
     <form id="expForm" 	name="expForm"	onSubmit="return false"	>
      <div id="fullWidth" nowrap="nowrap">
       <table>
        <tbody class="subHeading3">
          ...... more form elements ......
          <tr>
      	<input type="text" id="PAYEE" size="60" maxlength="50" />	
          </tr>
          ...... more form elements .......
        </tbody>
       </table>
      </div>
     </form>
    </body>
    JS
    Code:
    function myStartUp(){
     var oTextbox = new AutoSuggestControl(document.getElementById("PAYEE"), new PayeeSuggestions());        
    }
    
    function PayeeSuggestions() {
    	this.payee = ["List","Of","Suggestions","For","This","Field"];
    }
    
    PayeeSuggestions.prototype.requestSuggestions = 
    	function (oAutoSuggestControl /*:AutoSuggestControl*/) {
    		var aSuggestions = [];
    		var sTextboxValue = oAutoSuggestControl.textbox.value;
    
    		if (sTextboxValue.length > 0){
    
    			//search for matching record
    			for (var i=0; i < this.payee.length; i++) { 
    				if (this.payee[i].indexOf(sTextboxValue.toUpperCase()) == 0) {
    					aSuggestions.push(this.payee[i]);
    				} 
    			}
    		}
    
    		//provide suggestions to the control
    		oAutoSuggestControl.autosuggest(aSuggestions);
    	}

    The autosuggest code.
    Code:
    /**
     * 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;
        
        //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*/) {
        
        //make sure there's at least one suggestion
        if (aSuggestions.length > 0) {
            if (bTypeAhead) {
               this.typeAhead(aSuggestions[0]);
            }
            
            this.showSuggestions(aSuggestions);
        } else {
            this.hideSuggestions();
        }
    };
    
    /**
     * Creates the dropdown layer to display multiple suggestions.
     * @scope private
     */
    AutoSuggestControl.prototype.createDropDown = function () {
    
        var oThis = this;
    
        //create the layer and assign styles
        this.layer = document.createElement("div");
        this.layer.className = "suggestions";
        this.layer.style.visibility = "hidden";
        this.layer.style.width = this.textbox.offsetWidth;
        
        //when the user clicks on the a suggestion, get the text (innerHTML)
        //and place it into a textbox
        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();
            }
        };
        
        
        document.body.appendChild(this.layer);
    };
    
    /**
     * 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;
    };
    
    /**
     * 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.previousSuggestion();
                break;
            case 40: //down arrow 
                this.nextSuggestion();
                break;
            case 13: //enter
                this.hideSuggestions();
                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;
    
        //for backspace (8) and delete (46), shows suggestions without typeahead
        if (iKeyCode == 8 || iKeyCode == 46) {
            this.provider.requestSuggestions(this, false);
            
        //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.provider.requestSuggestions(this, true);
        }
    };
    
    /**
     * Hides the suggestion dropdown.
     * @scope private
     */
    AutoSuggestControl.prototype.hideSuggestions = function () {
        this.layer.style.visibility = "hidden";
    };
    
    /**
     * 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();
    };
    
    /**
     * Highlights the next suggestion in the dropdown and
     * places the suggestion into the textbox.
     * @scope private
     */
    AutoSuggestControl.prototype.nextSuggestion = function () {
        var cSuggestionNodes = this.layer.childNodes;
    
        if (cSuggestionNodes.length > 0 && this.cur < cSuggestionNodes.length-1) {
            var oNode = cSuggestionNodes[++this.cur];
            this.highlightSuggestion(oNode);
            this.textbox.value = oNode.firstChild.nodeValue; 
        }
    };
    
    /**
     * Highlights the previous suggestion in the dropdown and
     * places the suggestion into the textbox.
     * @scope private
     */
    AutoSuggestControl.prototype.previousSuggestion = function () {
        var cSuggestionNodes = this.layer.childNodes;
    
        if (cSuggestionNodes.length > 0 && this.cur > 0) {
            var oNode = cSuggestionNodes[--this.cur];
            this.highlightSuggestion(oNode);
            this.textbox.value = oNode.firstChild.nodeValue;   
        }
    };
    
    /**
     * Selects a range of text in the textbox.
     * @scope public
     * @param iStart The start index (base 0) of the selection.
     * @param iLength The number of characters to select.
     */
    AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {
    
        //use text ranges for Internet Explorer
        if (this.textbox.createTextRange) {
            var oRange = this.textbox.createTextRange(); 
            oRange.moveStart("character", iStart); 
            oRange.moveEnd("character", iLength - this.textbox.value.length);      
            oRange.select();
            
        //use setSelectionRange() for Mozilla
        } else if (this.textbox.setSelectionRange) {
            this.textbox.setSelectionRange(iStart, iLength);
        }     
    
        //set focus back to the textbox
        this.textbox.focus();      
    }; 
    
    /**
     * 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(aSuggestions[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.position = "absolute";
    	[B]this.layer.style.z-index = 200;[/B]
        this.layer.style.visibility = "visible";
    
    };
    
    /**
     * 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);
        }
    };
  • JKing
    Recognized Expert Top Contributor
    • Jun 2007
    • 1206

    #2
    In javascript, having a variable/property with a '-' is illegal as it is interpreted as mathematical operation.

    The proper syntax for the z-index property is as follows:
    Code:
    this.layer.style.zIndex = 200;

    Comment

    • Claus Mygind
      Contributor
      • Mar 2008
      • 571

      #3
      Well that solved the first problem. But my layer is still buried behind the first layer. How can I make my suggestions appear on top?

      Comment

      • Claus Mygind
        Contributor
        • Mar 2008
        • 571

        #4
        Well I solved the problem by removing the z-index in the .css file for the <div> that was covering the autosuggest response
        Code:
         #fullWidth {
             position: absolute;
             white-space: nowrap; 
             left: 0%; 
             top: 25px;
             width: 99%;
             color: #333333;
             padding:5px;
             font-size: 10pt;
             overflow: hidden;
        [B]     z-index: 98;[/B]
         }
        Not sure why that should fix it as the z-index for the autosuggest was set to 200 and both had absolute positioning. but it worked.

        Comment

        Working...