By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,504 Members | 1,190 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,504 IT Pros & Developers. It's quick & easy.

Making autosuggest top layer

Claus Mygind
100+
P: 571
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 "autosuggest code" where I have also highlighted the code.
Expand|Select|Wrap|Line Numbers
  1.     this.layer.style.left = this.getLeft() + "px";
  2.     this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
  3.     this.layer.style.position = "absolute";
  4.     this.layer.style.z-index = 200;
  5.     this.layer.style.visibility = "visible";
  6.  
  7. };


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

The autosuggest code.
Expand|Select|Wrap|Line Numbers
  1.  
  2. /**
  3.  * An autosuggest textbox control.
  4.  * @class
  5.  * @scope public
  6.  */
  7. function AutoSuggestControl(oTextbox /*:HTMLInputElement*/, 
  8.                             oProvider /*:SuggestionProvider*/) {
  9.  
  10.     /**
  11.      * The currently selected suggestions.
  12.      * @scope private
  13.      */   
  14.     this.cur /*:int*/ = -1;
  15.  
  16.     /**
  17.      * The dropdown list layer.
  18.      * @scope private
  19.      */
  20.     this.layer = null;
  21.  
  22.     /**
  23.      * Suggestion provider for the autosuggest feature.
  24.      * @scope private.
  25.      */
  26.     this.provider /*:SuggestionProvider*/ = oProvider;
  27.  
  28.     /**
  29.      * The textbox to capture.
  30.      * @scope private
  31.      */
  32.     this.textbox /*:HTMLInputElement*/ = oTextbox;
  33.  
  34.     //initialize the control
  35.     this.init();
  36.  
  37. }
  38.  
  39. /**
  40.  * Autosuggests one or more suggestions for what the user has typed.
  41.  * If no suggestions are passed in, then no autosuggest occurs.
  42.  * @scope private
  43.  * @param aSuggestions An array of suggestion strings.
  44.  * @param bTypeAhead If the control should provide a type ahead suggestion.
  45.  */
  46. AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/,
  47.                                                      bTypeAhead /*:boolean*/) {
  48.  
  49.     //make sure there's at least one suggestion
  50.     if (aSuggestions.length > 0) {
  51.         if (bTypeAhead) {
  52.            this.typeAhead(aSuggestions[0]);
  53.         }
  54.  
  55.         this.showSuggestions(aSuggestions);
  56.     } else {
  57.         this.hideSuggestions();
  58.     }
  59. };
  60.  
  61. /**
  62.  * Creates the dropdown layer to display multiple suggestions.
  63.  * @scope private
  64.  */
  65. AutoSuggestControl.prototype.createDropDown = function () {
  66.  
  67.     var oThis = this;
  68.  
  69.     //create the layer and assign styles
  70.     this.layer = document.createElement("div");
  71.     this.layer.className = "suggestions";
  72.     this.layer.style.visibility = "hidden";
  73.     this.layer.style.width = this.textbox.offsetWidth;
  74.  
  75.     //when the user clicks on the a suggestion, get the text (innerHTML)
  76.     //and place it into a textbox
  77.     this.layer.onmousedown = 
  78.     this.layer.onmouseup = 
  79.     this.layer.onmouseover = function (oEvent) {
  80.         oEvent = oEvent || window.event;
  81.         oTarget = oEvent.target || oEvent.srcElement;
  82.  
  83.         if (oEvent.type == "mousedown") {
  84.             oThis.textbox.value = oTarget.firstChild.nodeValue;
  85.             oThis.hideSuggestions();
  86.         } else if (oEvent.type == "mouseover") {
  87.             oThis.highlightSuggestion(oTarget);
  88.         } else {
  89.             oThis.textbox.focus();
  90.         }
  91.     };
  92.  
  93.  
  94.     document.body.appendChild(this.layer);
  95. };
  96.  
  97. /**
  98.  * Gets the left coordinate of the textbox.
  99.  * @scope private
  100.  * @return The left coordinate of the textbox in pixels.
  101.  */
  102. AutoSuggestControl.prototype.getLeft = function () /*:int*/ {
  103.  
  104.     var oNode = this.textbox;
  105.     var iLeft = 0;
  106.  
  107.     while(oNode.tagName != "BODY") {
  108.         iLeft += oNode.offsetLeft;
  109.         oNode = oNode.offsetParent;        
  110.     }
  111.  
  112.     return iLeft;
  113. };
  114.  
  115. /**
  116.  * Gets the top coordinate of the textbox.
  117.  * @scope private
  118.  * @return The top coordinate of the textbox in pixels.
  119.  */
  120. AutoSuggestControl.prototype.getTop = function () /*:int*/ {
  121.  
  122.     var oNode = this.textbox;
  123.     var iTop = 0;
  124.  
  125.     while(oNode.tagName != "BODY") {
  126.         iTop += oNode.offsetTop;
  127.         oNode = oNode.offsetParent;
  128.     }
  129.  
  130.     return iTop;
  131. };
  132.  
  133. /**
  134.  * Handles three keydown events.
  135.  * @scope private
  136.  * @param oEvent The event object for the keydown event.
  137.  */
  138. AutoSuggestControl.prototype.handleKeyDown = function (oEvent /*:Event*/) {
  139.  
  140.     switch(oEvent.keyCode) {
  141.         case 38: //up arrow
  142.             this.previousSuggestion();
  143.             break;
  144.         case 40: //down arrow 
  145.             this.nextSuggestion();
  146.             break;
  147.         case 13: //enter
  148.             this.hideSuggestions();
  149.             break;
  150.     }
  151.  
  152. };
  153.  
  154. /**
  155.  * Handles keyup events.
  156.  * @scope private
  157.  * @param oEvent The event object for the keyup event.
  158.  */
  159. AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) {
  160.  
  161.     var iKeyCode = oEvent.keyCode;
  162.  
  163.     //for backspace (8) and delete (46), shows suggestions without typeahead
  164.     if (iKeyCode == 8 || iKeyCode == 46) {
  165.         this.provider.requestSuggestions(this, false);
  166.  
  167.     //make sure not to interfere with non-character keys
  168.     } else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123)) {
  169.         //ignore
  170.     } else {
  171.         //request suggestions from the suggestion provider with typeahead
  172.         this.provider.requestSuggestions(this, true);
  173.     }
  174. };
  175.  
  176. /**
  177.  * Hides the suggestion dropdown.
  178.  * @scope private
  179.  */
  180. AutoSuggestControl.prototype.hideSuggestions = function () {
  181.     this.layer.style.visibility = "hidden";
  182. };
  183.  
  184. /**
  185.  * Highlights the given node in the suggestions dropdown.
  186.  * @scope private
  187.  * @param oSuggestionNode The node representing a suggestion in the dropdown.
  188.  */
  189. AutoSuggestControl.prototype.highlightSuggestion = function (oSuggestionNode) {
  190.  
  191.     for (var i=0; i < this.layer.childNodes.length; i++) {
  192.         var oNode = this.layer.childNodes[i];
  193.         if (oNode == oSuggestionNode) {
  194.             oNode.className = "current"
  195.         } else if (oNode.className == "current") {
  196.             oNode.className = "";
  197.         }
  198.     }
  199. };
  200.  
  201. /**
  202.  * Initializes the textbox with event handlers for
  203.  * auto suggest functionality.
  204.  * @scope private
  205.  */
  206. AutoSuggestControl.prototype.init = function () {
  207.  
  208.     //save a reference to this object
  209.     var oThis = this;
  210.  
  211.     //assign the onkeyup event handler
  212.     this.textbox.onkeyup = function (oEvent) {
  213.  
  214.         //check for the proper location of the event object
  215.         if (!oEvent) {
  216.             oEvent = window.event;
  217.         }    
  218.  
  219.         //call the handleKeyUp() method with the event object
  220.         oThis.handleKeyUp(oEvent);
  221.     };
  222.  
  223.     //assign onkeydown event handler
  224.     this.textbox.onkeydown = function (oEvent) {
  225.  
  226.         //check for the proper location of the event object
  227.         if (!oEvent) {
  228.             oEvent = window.event;
  229.         }    
  230.  
  231.         //call the handleKeyDown() method with the event object
  232.         oThis.handleKeyDown(oEvent);
  233.     };
  234.  
  235.     //assign onblur event handler (hides suggestions)    
  236.     this.textbox.onblur = function () {
  237.         oThis.hideSuggestions();
  238.     };
  239.  
  240.     //create the suggestions dropdown
  241.     this.createDropDown();
  242. };
  243.  
  244. /**
  245.  * Highlights the next suggestion in the dropdown and
  246.  * places the suggestion into the textbox.
  247.  * @scope private
  248.  */
  249. AutoSuggestControl.prototype.nextSuggestion = function () {
  250.     var cSuggestionNodes = this.layer.childNodes;
  251.  
  252.     if (cSuggestionNodes.length > 0 && this.cur < cSuggestionNodes.length-1) {
  253.         var oNode = cSuggestionNodes[++this.cur];
  254.         this.highlightSuggestion(oNode);
  255.         this.textbox.value = oNode.firstChild.nodeValue; 
  256.     }
  257. };
  258.  
  259. /**
  260.  * Highlights the previous suggestion in the dropdown and
  261.  * places the suggestion into the textbox.
  262.  * @scope private
  263.  */
  264. AutoSuggestControl.prototype.previousSuggestion = function () {
  265.     var cSuggestionNodes = this.layer.childNodes;
  266.  
  267.     if (cSuggestionNodes.length > 0 && this.cur > 0) {
  268.         var oNode = cSuggestionNodes[--this.cur];
  269.         this.highlightSuggestion(oNode);
  270.         this.textbox.value = oNode.firstChild.nodeValue;   
  271.     }
  272. };
  273.  
  274. /**
  275.  * Selects a range of text in the textbox.
  276.  * @scope public
  277.  * @param iStart The start index (base 0) of the selection.
  278.  * @param iLength The number of characters to select.
  279.  */
  280. AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {
  281.  
  282.     //use text ranges for Internet Explorer
  283.     if (this.textbox.createTextRange) {
  284.         var oRange = this.textbox.createTextRange(); 
  285.         oRange.moveStart("character", iStart); 
  286.         oRange.moveEnd("character", iLength - this.textbox.value.length);      
  287.         oRange.select();
  288.  
  289.     //use setSelectionRange() for Mozilla
  290.     } else if (this.textbox.setSelectionRange) {
  291.         this.textbox.setSelectionRange(iStart, iLength);
  292.     }     
  293.  
  294.     //set focus back to the textbox
  295.     this.textbox.focus();      
  296. }; 
  297.  
  298. /**
  299.  * Builds the suggestion layer contents, moves it into position,
  300.  * and displays the layer.
  301.  * @scope private
  302.  * @param aSuggestions An array of suggestions for the control.
  303.  */
  304. AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/) {
  305.  
  306.     var oDiv = null;
  307.     this.layer.innerHTML = "";  //clear contents of the layer
  308.  
  309.     for (var i=0; i < aSuggestions.length; i++) {
  310.         oDiv = document.createElement("div");
  311.         oDiv.appendChild(document.createTextNode(aSuggestions[i]));
  312.         this.layer.appendChild(oDiv);
  313.     }
  314.  
  315.     this.layer.style.left = this.getLeft() + "px";
  316.     this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
  317.     this.layer.style.position = "absolute";
  318.     this.layer.style.z-index = 200;
  319.     this.layer.style.visibility = "visible";
  320.  
  321. };
  322.  
  323. /**
  324.  * Inserts a suggestion into the textbox, highlighting the 
  325.  * suggested part of the text.
  326.  * @scope private
  327.  * @param sSuggestion The suggestion for the textbox.
  328.  */
  329. AutoSuggestControl.prototype.typeAhead = function (sSuggestion /*:String*/) {
  330.  
  331.     //check for support of typeahead functionality
  332.     if (this.textbox.createTextRange || this.textbox.setSelectionRange){
  333.         var iLen = this.textbox.value.length; 
  334.         this.textbox.value = sSuggestion; 
  335.         this.selectRange(iLen, sSuggestion.length);
  336.     }
  337. };
  338.  
  339.  
May 14 '11 #1

✓ answered by Claus Mygind

Well I solved the problem by removing the z-index in the .css file for the <div> that was covering the autosuggest response
Expand|Select|Wrap|Line Numbers
  1.  #fullWidth {
  2.      position: absolute;
  3.      white-space: nowrap; 
  4.      left: 0%; 
  5.      top: 25px;
  6.      width: 99%;
  7.      color: #333333;
  8.      padding:5px;
  9.      font-size: 10pt;
  10.      overflow: hidden;
  11.      z-index: 98;
  12.  }
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.

Share this Question
Share on Google+
3 Replies


JKing
Expert 100+
P: 1,206
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:
Expand|Select|Wrap|Line Numbers
  1. this.layer.style.zIndex = 200;
  2.  
May 15 '11 #2

Claus Mygind
100+
P: 571
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?
May 15 '11 #3

Claus Mygind
100+
P: 571
Well I solved the problem by removing the z-index in the .css file for the <div> that was covering the autosuggest response
Expand|Select|Wrap|Line Numbers
  1.  #fullWidth {
  2.      position: absolute;
  3.      white-space: nowrap; 
  4.      left: 0%; 
  5.      top: 25px;
  6.      width: 99%;
  7.      color: #333333;
  8.      padding:5px;
  9.      font-size: 10pt;
  10.      overflow: hidden;
  11.      z-index: 98;
  12.  }
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.
May 16 '11 #4

Post your reply

Sign in to post your reply or Sign up for a free account.