martin_borman martin_borman - 5 months ago 8
Javascript Question

Getting the wrong element in click handler with overlapping "circle" divs

I am trying dynamically add HTML elements with click handlers. When the click handler is activated it targets wrong element. Where could be the problem?



(function() {

//selector, jQuery style
var $ = function(selector) {
return document.querySelector(selector);
}

//getting quantity of circles
var quantity = $('.circles').getAttribute('quantity');

//setting outer width/height for circles
$('.circles').style.width = (quantity * 50) + 4 + 'px';
$('.circles').style.height = (quantity * 50) + 4 + 'px';

//creating element for children
var childCircle = document.createElement('div');
childCircle.className = 'subCircle';

//click function for children
function onClick() {
this.attributes.style.value += 'border-color: red;'
alert(this.clientHeight);
}

//append sub circles
for (var i = 0; i < quantity; i++) {
$('.circles').appendChild(childCircle.cloneNode());
}

//iterate over .circles .subCircle and add onClick function for each subCircle and css aswell

var subCircle = $('.circles').getElementsByClassName('subCircle');
for (var i = 0; i < subCircle.length; i++) {
subCircle[i].onclick = onClick;
subCircle[i].style.width = ((i + 1) * 50) + 'px';
subCircle[i].style.height = ((i + 1) * 50) + 'px';
}

})();

.circles {
position: absolute;
}

.subCircle {
position: absolute;
border-radius: 50%;
transform: translateX(-50%) translateY(-50%);
border: 2px solid black;
top: 50%;
left: 50%;
}

<body>
<div class="circles" quantity=10></div>
</body>





Also on jsFiddle: https://jsfiddle.net/martin_borman/1srkL5bf/

Answer

The problem isn't this, which is actually getting set by the event callback mechanism just fine. It's that your largest circle is on top.

Changing the loop that sets the size lets you put the smaller circles on top:

for (var i = 0; i < subCircle.length; i++) {
  subCircle[i].onclick = onClick;
  subCircle[i].style.width = ((subCircle.length - i) * 50) + 'px';
  subCircle[i].style.height = ((subCircle.length - i) * 50) + 'px';
}

The key bit there is (subCircle.length - i) * 50 rather than (i + 1) * 50.

I'd also use

this.style.borderColor = 'red';

rather than

this.attributes.style.value += 'border-color: red;'

Example:

(function() {

  //selector, jQuery style
  var $ = function(selector) {
    return document.querySelector(selector);
  }

  //getting quantity of circles
  var quantity = $('.circles').getAttribute('quantity');

  //setting outer width/height for circles
  $('.circles').style.width = (quantity * 50) + 4 + 'px';
  $('.circles').style.height = (quantity * 50) + 4 + 'px';

  //creating element for children
  var childCircle = document.createElement('div');
  childCircle.className = 'subCircle';

  //click function for children
  function onClick() {
    this.style.borderColor = 'red';
    alert(this.clientHeight);
  }

  //append sub circles
  for (var i = 0; i < quantity; i++) {
    $('.circles').appendChild(childCircle.cloneNode());
  }

  //iterate over .circles .subCircle and add onClick function for each subCircle and css aswell

  var subCircle = $('.circles').getElementsByClassName('subCircle');
  for (var i = 0; i < subCircle.length; i++) {
    subCircle[i].onclick = onClick;
    subCircle[i].style.width = ((subCircle.length - i) * 50) + 'px';
    subCircle[i].style.height = ((subCircle.length - i) * 50) + 'px';
  }

})();
.circles {
  position: absolute;
}

.subCircle {
  position: absolute;
  border-radius: 50%;
  transform: translateX(-50%) translateY(-50%);
  border: 2px solid black;
  top: 50%;
  left: 50%;
}
<body>
  <div class="circles" quantity=10></div>
</body>

Comments