Unintended Div Build-Up

How do I keep the red divs from building up (one under another) with each onclick event? I tested variations of removeChild(div) without success. Is removeChild(div) part of the answer and I’m just using it wrong or is there a better approach?

<html>
<head>
<script type="text/javascript">
function showHint(str) {
  if (str.length==0) {
    document.getElementById("txtHint").innerHTML="";
    return;
  }
  if (window.XMLHttpRequest) {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();
    } else {
   	  // code for IE6, IE5
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
  xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState==4 && xmlhttp.status==200) {
	  var div = document.createElement('div');
      div.setAttribute('id', 'link_container');
      div.setAttribute("style","background-color:red;");
      //div.style.backgroundColor = 'red';
      div.style.width = '300px';
      div.style.height = '100px';
      div.style.margin = '-15px 0px 0px 75px';
      var txt=xmlhttp.responseText;
      var strA = txt.slice(0,txt.indexOf(",")); //define number of cycles of For Loop 
      var str = txt.substr(txt.indexOf(",")+1);  //cut 1st position from string and save remaining info
      for (i=0; i<=strA; i++){
        var newLink = document.createElement('a'); //create anchor
        var linkName = str.slice(0,str.indexOf(" ,")+1);
        var linkName = linkName.split(' ').join(''); 
        newLink.href = "http://localhost/" + linkName+".php";
        newLink.innerHTML = linkName;
	var str = str.substr(str.indexOf(",")+1);
	div.appendChild(newLink);
	var newBr = document.createElement('br'); //create break
	div.appendChild(newBr);
      }
	  //document.getElementsByTagName('body')[0].removeChild(div);
	  document.getElementsByTagName('body')[0].appendChild(div);
	}
  }
  xmlhttp.open("GET","gethint.php?q="+str,true);
  xmlhttp.send();
}
</script>
</head>
<body>
  <p><b>Start typing a name in the input field below:</b></p>
  <form>
    First name: <input type="text" onkeyup="showHint(this.value)" size="20" />
  </form>
 
</body>
</html>

The “div” variable only refers to the element your JavaScript has just created, which has not yet been added to the DOM.

But because you give the div an id, there’s a pretty quick fix. Before you append the new div, first check to see if an element already exists in the document with that id. (It shouldn’t exist when the code is executed the first time.) If it does exist, simply remove it from its parent, and you’re good to go!

Also, as I was looking through your code, a few things jumped out that could be improved:

  • You can use “document.body” instead of “document.getElementsByTagName(‘body’)[0]”
  • You can set an element’s id by using “div.id = ‘link_container’;” instead of “div.setAttribute(‘id’, ‘link_container’);”
  • According to QuirksMode, when using “setAttribute”, IE5-7 don’t set styles.
  • When sending a GET request, some versions of Firefox (and maybe other browsers, I can’t remember) throw an error if you just do “xmlhttp.send();” – pass null to fix this: “xmlhttp.send(null);”
  • There’s no element on the page with an id of “txtHint”, so if the input’s length is ever zero, your code will generate an error. (Did you change the id to “link_container” and then forget to change it in that if statement?)
  • You don’t use the “var” keyword when you create the “xmlhttp” variable. This isn’t necessarily a bug, but it means you’re making it a global variable. Were you aware that was happening? Was that the intention?
  • You’re creating a lot of variables (with the “var” keyword) inside that for-loop. It makes me cringe, but it’s definitely not a bug. (It might throw an error in strict mode or later versions of ECMAScript, but you’re fine.) If you have the time, you might want to check out this question on Stack Overflow: JavaScript variables declare outside or inside loop?

That’s probably a whole lot more than you bargained for, but I’m bored, so :stuck_out_tongue:

Thanks for all your help.

I’ve been working on this for hours and can’t seem to get removeChild() to work. I’m pretty sure that needs to be done in a javascript at the end of my file. IDs are supposed to always be unique. So, if document.getElementsByTagName(‘body’)[0].appendChild(div); adds the div. I expected something like this:
document.getElementsByTagName(‘body’).removeChild(div); at the end of the script to remove it, but nogo.

I placed this at the end of my code, based on your post, but nogo again.

var deleteDiv = document.getElementsById(‘link_container’);
document.getElementsByTagName(‘body’).removeChild(deleteDiv);

How do I remove an element by targeting it’s ID?

I think the only reason your “nogo again” code didn’t work is because of a couple of typos:

  • It’s “getElementById”, not “getElementsById”.
  • “document.getElementsByTagName(‘body’)” returns an array, not an element. Try using “document.body.removeChild(deleteDiv)” instead.

Does it work if you make those changes?

Thank-you.

I put this at the end of my code thinking that after the div displays (id = ‘link_container’) I can eliminate (id = ‘link_container’) from memory when the script ends so there’s a place for another div (id = ‘link_container’) when/if there’s onkeyup event.

<script type=“text/javascript”>
var deleteDiv = document.getElementById(‘link_container’);
document.body.removeChild(deleteDiv);
</script>

Wouldn’t this little script remove any element with an id = ‘link_container’ ?

You should only ever have one element on the page with any particular id. There should never be any confusion as to which element will be removed; it should always be the only element that has that id.

That being said, browsers can sometimes allow things that aren’t right. Does your code work? Does it remove the first square, and leave the new one that was just appended?

If it doesn’t work, try moving those two lines to just before where you add the new div, so that you’re (1) removing the old one, and then (2) appending the new one.

Off Topic:

Just wanted to correct a mistake in my earlier post, but couldn’t figure out how to edit it: getElementsByTagName doesn’t return an array, it returns an array-like object called a nodeList. If you’re interested, here’s an article detailing the differences between arrays and nodeLists. It’s from a pretty decent website; it looks good, I’m going to check more of it out later.

I know about the Hylander principle RE: IDs (there can only be one). That’s how I remember that. The dupe IDs is a by-product of the dupe divs.

The script works, but it appends a new div (with the correct results) under the existing div(s) with each onkeyup event. I just can’t find a place to insert my if statement (I decided the removeChild needs to be in an if).

Here’s my if :


if (document.getElementById('link_container')) {
        var deleteDiv = document.getElementById('link_container');
        document.parentNode.removeChild(deleteDiv);
  }

If you’d like to see what i’m seeing, here’s the php that goes with the script in post #1. Name it gethint.php. If i haven’t said it yet these scripts are for learning purposes for me. NOTE: the text hint only works by entering in a “b” or “br” … etc

the php:


<?php

// Fill up array with names
$a[]="Bob";
$a[]="Brittany";
$a[]="Brian";
//$a = array('a'=>'Bob','b'=>'Brittany','c'=>'Brittany');
//echo var_dump($a) . '<br/>';

//get the q parameter from URL
$q=$_GET["q"];

//lookup all hints from array if length of q>0
if (strlen($q) > 0)
  {
  $hint="";
  for($i=0; $i<count($a); $i++)
    {
    if (strtolower($q)==strtolower(substr($a[$i],0,strlen($q))))
      {
      if ($hint=="")
        {
        $hint=$a[$i];
        }
      else
        {
        $hint=$hint." , ".$a[$i];
        }
      }
    }
  }

// Set output to "no suggestion" if no hint were found
// or to the correct values
if ($hint == "")
  {
  $response="no suggestion";
  }
else
  {
  $response=$hint;
  }
/*
$response = explode(",",$response);
$response2=  "'" . "a" . "' => " . $response[0] . "'" . "b" . "' => " . $response[1]; 

echo json_encode($response2) . '</br>'; 
echo $hint . '</br>';; 
*/ 


//$hint = array();
//for($i=0; $i<count($a); $i++) {
//    if (strtolower($q)==strtolower(substr($a[$i],0,strlen($q)))) {
//        $hint[] = $a[$i];
 //   }
//}

//echo json_encode($hint); 

//$response = "";
//echo '<span onclick="document.getElementById("field2").value=this.innerHTML">Jim</span></br>';
//echo "bob";
//output the response
//echo var_dump($response2);
  //$response = "66," . $response;  
$response = substr_count($response," ,") . "," . $response . " ,";  
echo ($response);

//$var = '<span onclick="document.getElementById('field2').value=this.innerHTML">Jim</span></br>';
?>

Thanks for all your help sdleihssirhc. I successfully changed the approach to targeting an existing div instead of creating them dynamically.

like this:


<html>
<head>
<script type="text/javascript">

function showHint(str) {
  //if (document.getElementById('link_container') {
  //alert('here');
  //}
  //var popup_elem=document.getElementById('link_container');
  //popup_elem.style.display = (popup_elem.style.display == 'block') ? 'none' : 'block';
  if (str.length==0) {
//    document.getElementById("txtHint").innerHTML="";
    return;
  }
  if (window.XMLHttpRequest) {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();
    } else {
   	  // code for IE6, IE5
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }

  xmlhttp.onreadystatechange=function() {

    if (xmlhttp.readyState==4 && xmlhttp.status==200) {
	  var div = document.getElementById('link_container'); //get the container on the page
      div.innerHTML = ''; //clear out the link container
	  /*var div = document.createElement('div');
      div.setAttribute('id', 'link_container');
      //div.setAttribute("style","background-color:red;");
      div.style.backgroundColor = 'red';
	  div.style.width = '300px';
      div.style.height = '100px';
	  div.style.margin = '-15px 0px 0px 75px';
	  //var txt=document.innerHTML=xmlhttp.responseText;
	  */
	  var txt=xmlhttp.responseText;
	  var strA = txt.slice(0,txt.indexOf(",")); //define number of cycles of For Loop
	  var str = txt.substr(txt.indexOf(",")+1);  //cut 1st position from string and save remaining info
	  for (i=0; i<=strA; i++){
	    var newLink = document.createElement('a'); //create anchor
		var linkName = str.slice(0,str.indexOf(" ,")+1);
		var linkName = linkName.split(' ').join('');
		newLink.href = "http://localhost/" + linkName+".php";
        newLink.innerHTML = linkName;
		var str = str.substr(str.indexOf(",")+1);
		div.appendChild(newLink);
		var newBr = document.createElement('br'); //create break
		div.appendChild(newBr);
	  } //close For Loop
	  //var myLinkContainer = document.getElementById('link_container');
	  //alert('myLinkContainer');


	  //document.getElementsByTagName('body')[0].appendChild(div);
	  //document.getElementsByTagName('body')[0].replaceChild(div,y);
	  //var replaceDiv = 1;
      //document.getElementById('link_container').innerHTML=str;
      //document.getElementById('link_container').appendChild(newLink);

	} //close if (xmlhttp.readyState==4 && xmlhttp.status==200) {
  } //close xmlhttp.onreadystatechange=function() {

  xmlhttp.open("GET","gethint.php?q="+str,true);
  xmlhttp.send();

}//close function showHint(str) {

</script>
<style type="text/css">
#link_container {
	background-color: red;
	width: 300px;
	height: 100px;
	margin: -15px 0px 0px 75px;
	display:block;
}
</style>
</head>
<body>
  <p><b>Start typing a name in the input field below:</b></p>
  <form>
    First name: <input type="text" onkeyup="showHint(this.value)" size="20" />

  </form>
 <div id="link_container"></div>
</body>
</html>