cDub
cDub

Reputation: 518

jQuery; remove clicked div from inside constructor function among other divs with same class

This is an assignment for school. One part of the assignment is to double click on a div that has been created inside of a class. When you double click on it, it should get deleted.

The html has a button that creates the div as an instance of the class. That worked fine. Then I put a double click event listener on the div's class and .remove() on a class method (see code).

But when double clicked, it deletes the div and all the divs after it. I believe this is happening because all the divs have the same class name.

I could assign ids to each div when they're created and delete that specific div. I'm just wondering if there is another way to grab the div that's clicked.

I also tried using 'this' to refer to the div clicked. However, I need 'this' to connect to the method 'this.removeOne' so I used an arrow function.

Basics of the code below. All the details here: https://jsfiddle.net/ChristyCakes/8w0htt1s/

Bottom Line: I want to double click on a div and remove only that one div. Is giving it an id the only way?

This question is very similar to other ones on stack, but I'm having trouble applying the answers to this particular situation - or I need clearer explanation.

// create a class called Die
class Die {
  constructor(value) {

    // set value property
    this.value = value;

    // create a div for each new object, assign class
    this.div = $('<div></div>').attr("class", "div");
    $(this.div).append(this.value);
    $('.container').append(this.div);

    // when Roll All Dice button is clicked, run the rollAll method (below)
    $('#all').click(() => this.rollAll());

    // when a div is clicked, run rollOne function below
    $('.div').click(() => this.rollOne());

    // when any div is double clicked, run removeOne function below
    $('.div').dblclick(() => this.removeOne());
  }

  // roll all dice again; get random number, replace value in div
  rollAll() {
    this.value = Math.floor(Math.random() * 6 + 1);
    $(this.div).html(this.value);
  }

  // roll the clicked dice again
  rollOne() {
    this.value = Math.floor(Math.random() * 6 + 1);
    $(this.div).html(this.value);
  }

  //remove die that was clicked from display and from sumable dice
  removeOne() {
    $(this.div).remove();
  }

}

// when Add All Dice button is clicked, add value (text) in each div, display sum as alert
$('#sum').click(function() {
  let sum = 0;
  $('.div').each(function() {
    sum += parseFloat($(this).text()); //parseFloat turns strings into sumable numbers
  })
  alert(sum);
})

// Roll 1 Die button generates random number, creates an instance of Die class
$('#btn').click(function roll() {
  let val = Math.floor(Math.random() * 6 + 1);
  let die = new Die(val);
})
.div {
  border: 1rem solid black;
  height: 20rem;
  width: 20%;
  float: left;
  display: flex;
  align-items: center;
  justify-content: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Dicey Business</h1>
<div class="container">
  <div>
    <button id="btn">Roll 1 Die</button>
    <button id="all">Roll All Dice</button>
    <button id="sum">Add All Dice</button>
  </div>
</div>

Upvotes: 1

Views: 61

Answers (2)

Tim Gupta
Tim Gupta

Reputation: 104

You should be able to pass the element that is double-clicked to removeOne by getting it from the event object that is given to all event handlers:

$('.div').dblclick((event) => this.removeOne(event.target));

Then in removeOne you can do:

removeOne(elem) {
  $(elem).remove();
}

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370979

Currently, each instantiation is attaching a remove-this-div-on-click listener to all .divs:

$('.div').click(() => this.removeOne());

So, when any .div is clicked, every listener triggers, and all are removed. Instead, in the constructor, only attach the listener to the newly created .div:

$(this.div).dblclick(() => this.removeOne());

// create a class called Die
class Die {
  constructor(value) {

    // set value property
    this.value = value;

    // create a div for each new object, assign class
    this.div = $('<div></div>').attr("class", "div");
    $(this.div).append(this.value);
    $('.container').append(this.div);

    // when Roll All Dice button is clicked, run the rollAll method (below)
    $('#all').click(() => this.rollAll());

    // when a div is clicked, run rollOne function below
    $(this.div).click(() => this.rollOne());

    // when any div is double clicked, run removeOne function below
    $(this.div).dblclick(() => this.removeOne());
  }

  // roll all dice again; get random number, replace value in div
  rollAll() {
    this.value = Math.floor(Math.random() * 6 + 1);
    $(this.div).html(this.value);
  }

  // roll the clicked dice again
  rollOne() {
    this.value = Math.floor(Math.random() * 6 + 1);
    $(this.div).html(this.value);
  }

  //remove die that was clicked from display and from sumable dice
  removeOne() {
    $(this.div).remove();
  }

}

// when Add All Dice button is clicked, add value (text) in each div, display sum as alert
$('#sum').click(function() {
  let sum = 0;
  $('.div').each(function() {
    sum += parseFloat($(this).text()); //parseFloat turns strings into sumable numbers
  })
  alert(sum);
})

// Roll 1 Die button generates random number, creates an instance of Die class
$('#btn').click(function roll() {
  let val = Math.floor(Math.random() * 6 + 1);
  let die = new Die(val);
})
.div {
  border: 1rem solid black;
  height: 20rem;
  width: 20%;
  float: left;
  display: flex;
  align-items: center;
  justify-content: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Dicey Business</h1>
<div class="container">
  <div>
    <button id="btn">Roll 1 Die</button>
    <button id="all">Roll All Dice</button>
    <button id="sum">Add All Dice</button>
  </div>
</div>

You also might consider naming the dice divs a bit more informatively - a class name of div sounds like a very easy source of confusion. (Maybe .die instead, for example?)

Upvotes: 1

Related Questions