RealAnyOne RealAnyOne - 3 years ago 136
HTML Question

How to remove a div without using its ID

Divs are created every update and their positions are randomized inside "levelWrapper". All these divs share a class named tree. Whenever I click a div that has tree as a class, the code runs through all existing tree classed divs and compares their positions in relation to the mouse click coordinates. If their position is within click range (which is 100px) then I want to remove said divs.

Here's what I have that already does what I want BUT bugs after the first run through the code. I think I know why it bugs, read below.



var i = 0,
a = 0;

function newTree() {
var newTree = document.createElement('div');
newTree.id = 'tree' + i;
newTree.className = 'tree';
document.getElementById("levelWrapper").appendChild(newTree);
}

function positionTree() {
var levelWidth = document.getElementById("levelWrapper").offsetWidth;
var levelHeight = document.getElementById("levelWrapper").offsetHeight;

var treeX = Math.round(Math.random() * levelWidth);
var treeY = Math.round(Math.random() * levelHeight);

document.getElementById("tree" + i).style.left = treeX + "px";
document.getElementById("tree" + i).style.top = treeY + "px";
}

function createTree() {
a += 1;
if (a == 20) {
newTree(); // new div
positionTree(); // position div
a = 0; // reset counter for new div
i++; // new ID for new div
}
}

function getMouseCoordinates(e) {
var offset = $('#levelWrapper').offset();
mouseX = Math.round(e.clientX - offset.left);
mouseY = Math.round(e.clientY - offset.top);
}

var clickRange = 100;

function update() {
createTree();

$('div.tree').click(function(e) {
getMouseCoordinates(e);
var numItems = $('.tree').length;

for (g = 0; g < numItems; g++) {
var p = $("#tree" + g).position();

if ((p.left > (mouseX - clickRange)) &
(p.left < (mouseX + clickRange)) &
(p.top > (mouseY - clickRange)) &
(p.top < (mouseY + clickRange))) {

p = document.getElementById("tree" + g);
p.parentNode.removeChild(p);
}
}
});
}

function mainLoop() {
update();
requestAnimationFrame(mainLoop);
}

requestAnimationFrame(mainLoop);

#levelWrapper {
position: relative;
top: 25px;
width: 1100px;
height: 700px;
margin: auto;
border: 1px solid red;
}

.tree {
position: absolute;
background: green;
height: 12px;
width: 12px;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="levelWrapper"></div>





It bugs because on the second run, this line
var p = $("#tree" + g).position();
selects a div that has been deleted so it returns a null.

New divs are still created, but the click/remove function stops working.

I could probably do something along the lines of "if (null) ..." BUT the div IDs keep increasing, easily getting up to 200+ divs that the for loop has to go through and that is visibly slow.

So instead of removing divs through their IDs, I thought of having some array referencing them and whenever I delete one div, the array "cascades" down, reducing the ammount of checking I have to do, and avoiding the null return whenever it tries to find the offset left and top of a removed div.

Answer Source
  1. test the existence:

   for (g = 0; g < numItems; g++) {
      var $div = $("#tree" + g);
      if ($div.length==0) continue;
      var p = $div.position();

      if ((p.left > (mouseX - clickRange)) &
        (p.left < (mouseX + clickRange)) &
        (p.top > (mouseY - clickRange)) &
        (p.top < (mouseY + clickRange))) {

        $div.remove();
      }
    }
  1. Delegate - You add a click handler every time you loop

 $('#levelWrapper').on('click','div.tree',function(e) {
  getMouseCoordinates(e);
  $('.tree').each(function() {
    var p = $(this).position();

var i = 0,
  a = 0;

function newTree() {
  i = $('#levelWrapper').children().length;
  var $newTree = $('<div/>', {
    'id': 'tree' + i,
    'class': 'tree'
  }); // .text(i); 
  $('#levelWrapper').append($newTree);
}

function positionTree() {
  var levelWidth = document.getElementById("levelWrapper").offsetWidth;
  var levelHeight = document.getElementById("levelWrapper").offsetHeight;

  var treeX = Math.round(Math.random() * levelWidth);
  var treeY = Math.round(Math.random() * levelHeight);

  document.getElementById("tree" + i).style.left = treeX + "px";
  document.getElementById("tree" + i).style.top = treeY + "px";
}

function createTree() {
  a += 1;
  if (a == 20) {
    newTree(); // new div
    positionTree(); // position div
    a = 0; // reset counter for new div
    i++; // new ID for new div
  }
}

function getMouseCoordinates(e) {
  var offset = $('#levelWrapper').offset();
  mouseX = Math.round(e.clientX - offset.left);
  mouseY = Math.round(e.clientY - offset.top);
}

var clickRange = 100;


function mainLoop() {
  createTree();
  requestAnimationFrame(mainLoop);
}


$(function() {
  $('#levelWrapper').on('click','div.tree',function(e) {
    getMouseCoordinates(e);
    $('.tree').each(function() {
      var p = $(this).position();

      if ((p.left > (mouseX - clickRange)) &
        (p.left < (mouseX + clickRange)) &
        (p.top > (mouseY - clickRange)) &
        (p.top < (mouseY + clickRange))) {

        $(this).remove();
      }
    });
  });
  requestAnimationFrame(mainLoop);
});
#levelWrapper {
  position: relative;
  top: 25px;
  width: 1100px;
  height: 700px;
  margin: auto;
  border: 1px solid red;
}

.tree {
  position: absolute;
  background: green;
  height: 12px;
  width: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="levelWrapper"></div>

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download