Home > Software engineering >  unselect a selected div
unselect a selected div

Time:06-26

I have 8 divs and when you click on a div it gets selected and its value will be added to an array. Once you select 5 divs the others will be set to "not selected" and you can't select any more divs. Now what I want is if you click on a selected div I want to remove the select feature from it and have its value removed from the array but my method is not working. How can I achieve this? Thanks in advance.

let testArray = []

$('.none').on('click', function() {
  if (testArray.length < 4) {
    testArray.push($(this).find('p').html())
    $(this).removeClass('none')
    $(this).addClass('selected')
  } else if (testArray.length == 4) {
    testArray.push($(this).find('p').html())
    $(this).removeClass('none')
    $(this).addClass('selected')
    console.log(testArray)
    $('.test').removeClass('none')
    $('.test:not(.selected)').addClass('notSelected')
  }
})

//not working
$('.selected').on('click', function() {
  var filteredArray = testArray.filter(function(e) {
    return e !== $(this).find('p').html()
  })
  testArray = filteredArray
  $(this).removeClass('selected')
  $('.test').removeClass('notSelected')
  $('.test:not(.selected)').addClass('none')
  console.log(testArray)
})
body {
  display: flex;
  flex-direction: row;
  justify-content: space-evenly;
}

.test {
  display: flex;
  width: 100px;
  height: 100px;
  border: 2px solid transparent;
  background-color: #000000;
  margin-left: 2%;
}

.selected {
  border: 2px solid green;
  cursor: pointer;
}

.notSelected {
  border: 2px solid red;
  cursor: default;
}

.none:hover {
  cursor: poiner;
}

.test p {
  color: #ffffff;
  margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<div >
  <p>test1</p>
</div>

<div >
  <p>test2</p>
</div>

<div >
  <p>test3</p>
</div>

<div >
  <p>test4</p>
</div>

<div >
  <p>test5</p>
</div>

<div >
  <p>test6</p>
</div>

<div >
  <p>test7</p>
</div>

<div >
  <p>test8</p>
</div>

CodePudding user response:

The issue with your current logic is because you need to use delegated event handlers. This is because you're dynamically adding/removing classes during runtime, yet the event handlers are only bound when the page loads, before the classes gett updated.

Also note that your logic is more complex than it needs to be. It can be simplified using toggleClass(). In addition you should avoid using global variables. Only generate the array of values when necessary. In this case that's when all selections have been made, however I extracted that logic to its own function so you can call it wherever necessary - under a button click for example. Finally, the use of cursor in the CSS can be DRY'd up slightly.

Here's a working demo with all the above issues addressed:

let $divs = $('.test');

let getSelectedItems = () => {
  let selectedItems = $divs.filter('.selected').map((i, el) => $(el).text().trim()).get();
  console.log(selectedItems);
}

$(document).on('click', '.none', function() {
  $(this).toggleClass('none selected');
  
  if ($divs.filter('.selected').length == 5) {
    $divs.removeClass('none').not('.selected').addClass('notSelected');
    getSelectedItems();
  }
})

$(document).on('click', '.selected', function() {
  $(this).removeClass('selected');
  $divs.removeClass('notSelected').filter(':not(.selected)').addClass('none');
});

$('button').on('click', () => getSelectedItems);
body {
  display: flex;
  flex-direction: row;
  justify-content: space-evenly;
}

.test {
  display: flex;
  width: 100px;
  height: 100px;
  border: 2px solid transparent;
  background-color: #000000;
  margin-left: 2%;
  cursor: pointer;
}

.selected {
  border: 2px solid green;
}

.test.notSelected {
  border: 2px solid red;
  cursor: default;
}

.test p {
  color: #ffffff;
  margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div ><p>test1</p></div>
<div ><p>test2</p></div>
<div ><p>test3</p></div>
<div ><p>test4</p></div>
<div ><p>test5</p></div>
<div ><p>test6</p></div>
<div ><p>test7</p></div>
<div ><p>test8</p></div>

<button>Get test array</button>

CodePudding user response:

I am going to propose an alternate solution - set a data attribute and then just toggle it.

Here I use the data values in the CSS so I don't have to toggle anything, just set the values. I put a couple buttons in place just to show what is happening and how to filter on those selected with the dataset values.

let testArray = [];
let allTestable = $('.none.test');
let howMany = allTestable.length;
let maxCanSelect = 5;

$('.none.test').on('click', function(event) {
  if (this.dataset.isselected == "true") {
    this.dataset.isselected = "false";
  } else {
    var setToFun = allTestable.filter(function() {
      return this.dataset.isselected == "true";
    }).length;
    if (setToFun < maxCanSelect) {
      this.dataset.isselected = "true"
    }
  }
});

/* from here down is just to show what we have- above is all we specifically need */
$('#choices-done').on('click', function(event) {
  testArray = [];
  allTestable.filter(function() {
    return this.dataset.isselected == "true";
  }).each(function() {
    testArray.push($(this).find('p').html());
  });
  $("#results").text(testArray);
});
$('#choices-restart').on('click reset', function(event) {
  allTestable.filter(function() {
    return this.dataset.isselected = "false";
  });
  testArray = [];
  $("#results").text("");
}).trigger("reset");
.choice-things {
  display: flex;
  flex-direction: row;
  justify-content: space-evenly;
}

.test {
  display: flex;
  width: 100px;
  height: 100px;
  border: 2px solid transparent;
  background-color: #000000;
  margin-left: 2%;
}

.test.none[data-isselected="true"] {
  border: 2px solid green;
  cursor: pointer;
}

.test.none[data-isselected="false"] {
  border: 2px solid red;
  cursor: default;
}

.none:hover {
  cursor: poiner;
}

.test p {
  color: #ffffff;
  margin: auto;
}

.action {
  display: flex;
  margin-top: 2em;
  align-self: bottom;
  justify-content: space-evenly;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
  <div >
    <p>test1</p>
  </div>
  <div >
    <p>test2</p>
  </div>
  <div >
    <p>test3</p>
  </div>
  <div >
    <p>test4</p>
  </div>
  <div >
    <p>test5</p>
  </div>
  <div >
    <p>test6</p>
  </div>
  <div >
    <p>test7</p>
  </div>
  <div >
    <p>test8</p>
  </div>
</div>
<div >
  <button type="button" id="choices-done">Done yet click here</button>
  <button type="button" id="choices-restart">Start over</button>
</div>
<div id="results"></div>

  • Related