Spanky
Spanky

Reputation: 709

How do you conditionally reset a counter in JavaScript

Currently I have a Thumbs up and Thumbs down button that allows the user to click thumbs-up and down multiple times keeps count of each item (Similar to YouTube). I would like to set it up where If a user clicks on thumbs down, the thumbs up count resets, and vice versa. Is there a way to do this conditionally?

$().ready(function() {
  display();
});

function display() {
  $("#book-items").html("");
  let content = "";
  let col = "";
  for (let i in GV_MOVIES) {
    content += "<li class='flex-item'>";
    col = `<div class="img-cnt"><img src='${GV_MOVIES[i].image}'/></div><div class="book-title"> ${GV_MOVIES[i].title} </div> `;
    content += col;
    let val = GV_MOVIES[i].thumbsUp + " +";
    content += "<div class='group'>";
    let btn = `<button class='btnUp' onClick='javascript:upClick(${i})'><div>${val}</div></button>`;
    content += btn;
    val = GV_MOVIES[i].thumbsDown + " -";
    btn = `<button class='btnDown' onClick='javascript:downClick(${i})'><div>${val}</div></button>`;
    content += btn + "</div>";
    content += "</div>";
  }
  $("#book-items").html(content);
}

function upClick(idx) {
  GV_MOVIES[idx].thumbsUp++;
  display();
}

function downClick(idx) {
  GV_MOVIES[idx].thumbsDown++;
  display();
}

//var GV_MOVIES = []
var GV_MOVIES = [{
    id: 1,
    title: "Anne of Greene Gables",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/cJmt614/greengable.jpg"
  },
  {
    id: 2,
    title: "Island Of The Blue Dolphins",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/y0PDkJP/dolphin.jpg"
  },
  {
    id: 3,
    title: "The Tipping Point",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/tp4H24J/tippingpoint.jpg"
  },
  {
    id: 4,
    title: "The Reckoning",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/3z0HWyw/reckomning.jpg"
  }
];
#book-items {
  display: flex;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  flex-flow: row wrap;
  justify-content: space-around;
  padding: 0;
  margin: 0;
  list-style: none;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  -webkit-box-align: stretch;
  -webkit-align-items: stretch;
  -ms-flex-align: stretch;
  align-items: stretch;
  -webkit-align-content: stretch;
  -ms-flex-line-pack: stretch;
  align-content: stretch;
}

.flex-item {
  background: #fff5f3;
  width: 180px;
  margin-top: 10px;
  font-weight: bold;
  font-size: 3em;
  text-align: center;
  padding: 16px;
}

img {
  width: 100%;
  height: auto;
}

.btnUp {
  background-image: url(https://i.ibb.co/H4MZMFT/thumbsupdown.png);
  background-repeat: no-repeat;
  background-position: 4px 0;
  background-clip: content-box;
  border: none;
}

button {
  position: relative;
}

.btnDown,
.btnUp {
  height: 50px;
  width: 50px;
  background-size: 80px;
}

.btnDown div,
.btnUp div {
  position: absolute;
  left: 19px;
  top: 60px;
}

.btnDown {
  background-image: url(https://i.ibb.co/H4MZMFT/thumbsupdown.png);
  background-repeat: no-repeat;
  background-position: -33px 0;
  background-clip: content-box;
  border: none;
}

.group {
  padding: 2px;
  height: 80px;
}

.book-title {
  font-size: 0.3em;
  font-family: arial;
  height: 59px;
  width: 50%;
  padding: 10px;
  display: table-cell;
  vertical-align: middle;
}

.img-cnt {
  width: 180px;
  height: 282px;
}

@media only screen and (min-device-width: 320px) and (max-device-width: 850px) {
  .flex-item {
    width: 470px;
    padding: 6px;
  }
  .img-cnt {
    width: 100%;
    height: auto;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='book-items'></div>

Upvotes: 1

Views: 184

Answers (3)

KooiInc
KooiInc

Reputation: 122888

It is generally not a good idea to use inline event handlers. Here's your snippet using Event Delegation and a data-attribute for identification of the clicked button. This way it's easy to identify the corresponding element of the GV_MOVIES array and modify the value of thumbsUp as well of that of thumbsDown.

I streamlined your code a bit. Toggling thumbsUp/-Down now does not require a complete rewrite of div#book-items anymore.

const GV_MOVIES = getData();
document.addEventListener('click', handle);
display();

function handle(evt) {
  if (evt.target.closest('[data-id]')) {
    return toggleUpDown(evt.target);
  }
}

function toggleUpDown(origin) {
  const clickedUp = origin.classList.contains("btnUp");
  GV_MOVIES[origin.dataset.id].thumbsUp = +(clickedUp);
  GV_MOVIES[origin.dataset.id].thumbsDown = +(!clickedUp);
  const parent = origin.closest('li');
  parent.querySelector(".btnUp [data-value]").dataset.value =
    `${GV_MOVIES[origin.dataset.id].thumbsUp} +`;
  parent.querySelector(".btnDown [data-value]").dataset.value =
    `${GV_MOVIES[origin.dataset.id].thumbsDown} -`;
}

function display() {
  const items = $("#book-items");
  items.html("");
  for (let i in GV_MOVIES) {
    items.append($(
      `<li class='flex-item'>
        <div class="img-cnt">
          <img src='${GV_MOVIES[i].image}'/>
        </div>
        <div class="book-title"> ${GV_MOVIES[i].title}</div>
        <div class='group'>
          <button class='btnUp' data-id='${i}'>
            <div data-value="${GV_MOVIES[i].thumbsUp + " +"}"></div>
          </button>
          <button class='btnDown' data-id='${i}'>
            <div data-value="${GV_MOVIES[i].thumbsDown + " -"}"></div>
          </button>
        </div>  
      </li>`));
  }
}

function getData() {
  return [{
      id: 1,
      title: "Anne of Greene Gables",
      thumbsUp: 0,
      thumbsDown: 0,
      image: "https://i.ibb.co/cJmt614/greengable.jpg"
    },
    {
      id: 2,
      title: "Island Of The Blue Dolphins",
      thumbsUp: 0,
      thumbsDown: 0,
      image: "https://i.ibb.co/y0PDkJP/dolphin.jpg"
    },
  ];
}
[data-value]:after {
  content: attr(data-value);
}

#book-items {
  display: flex;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  flex-flow: row wrap;
  justify-content: space-around;
  padding: 0;
  margin: 0;
  list-style: none;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  -webkit-box-align: stretch;
  -webkit-align-items: stretch;
  -ms-flex-align: stretch;
  align-items: stretch;
  -webkit-align-content: stretch;
  -ms-flex-line-pack: stretch;
  align-content: stretch;
}

.flex-item {
  background: #fff5f3;
  width: 180px;
  margin-top: 10px;
  font-weight: bold;
  font-size: 3em;
  text-align: center;
  padding: 16px;
}

img {
  width: 100%;
  height: auto;
}

.btnUp {
  background-image: url(https://i.ibb.co/H4MZMFT/thumbsupdown.png);
  background-repeat: no-repeat;
  background-position: 4px 0;
  background-clip: content-box;
  border: none;
}

button {
  position: relative;
}

.btnDown,
.btnUp {
  height: 50px;
  width: 50px;
  background-size: 80px;
}

.btnDown div,
.btnUp div {
  position: absolute;
  left: 19px;
  top: 60px;
}

.btnDown {
  background-image: url(https://i.ibb.co/H4MZMFT/thumbsupdown.png);
  background-repeat: no-repeat;
  background-position: -33px 0;
  background-clip: content-box;
  border: none;
}

.group {
  padding: 2px;
  height: 80px;
}

.book-title {
  font-size: 0.3em;
  font-family: arial;
  height: 59px;
  width: 50%;
  padding: 10px;
  display: table-cell;
  vertical-align: middle;
}

.img-cnt {
  width: 180px;
  height: 282px;
}

@media only screen and (min-device-width: 320px) and (max-device-width: 850px) {
  .flex-item {
    width: 470px;
    padding: 6px;
  }
  .img-cnt {
    width: 100%;
    height: auto;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='book-items'></div>

Upvotes: 1

mplungjan
mplungjan

Reputation: 177685

Here is an improved version which does not reload the list on every click

Also the generation of the display is vastly simplified and I use a data attribute for the storing of the index of the movie

Lastly I delegate the click to the container

$().ready(display);

function display() {
  $("#book-items").html(GV_MOVIES.map((movie, i) =>
      `<div class='flex-item'>
      <div class="img-cnt"><img src='${movie.image}'/></div>
      <div class="book-title">${movie.title}</div>
      <div class='group'>
        <button class='vote btnUp' data-idx="${i}">${movie.thumbsUp}</button>
        <button class='vote btnDown' data-idx="${i}">${movie.thumbsDown}</button>
      </div>
    </div>`).join("")
  )
  .on("click", ".vote", function() { // delegation
    const $parent = $(this).closest("div");
    const idx = $(this).data("idx");
    let val = +$(this).text();
    if (val === 0) $(this).text(1);
    $(this).siblings().eq(0).text(0);
    GV_MOVIES[idx].thumbsUp = $parent.find(".btnUp").text();
    GV_MOVIES[idx].thumbsDown = $parent.find(".btnDown").text();
  });
}


//var GV_MOVIES = []
var GV_MOVIES = [{
    id: 1,
    title: "Anne of Greene Gables",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/cJmt614/greengable.jpg"
  },
  {
    id: 2,
    title: "Island Of The Blue Dolphins",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/y0PDkJP/dolphin.jpg"
  },
  {
    id: 3,
    title: "The Tipping Point",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/tp4H24J/tippingpoint.jpg"
  },
  {
    id: 4,
    title: "The Reckoning",
    thumbsUp: 0,
    thumbsDown: 0,
    image: "https://i.ibb.co/3z0HWyw/reckomning.jpg"
  }
];
#book-items {
  display: flex;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  flex-flow: row wrap;
  justify-content: space-around;
  padding: 0;
  margin: 0;
  list-style: none;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  -webkit-box-align: stretch;
  -webkit-align-items: stretch;
  -ms-flex-align: stretch;
  align-items: stretch;
  -webkit-align-content: stretch;
  -ms-flex-line-pack: stretch;
  align-content: stretch;
}

.flex-item {
  background: #fff5f3;
  width: 180px;
  margin-top: 10px;
  font-weight: bold;
  font-size: 3em;
  text-align: center;
  padding: 16px;
}

img {
  width: 100%;
  height: auto;
}

.btnUp {
  background-image: url(https://i.ibb.co/H4MZMFT/thumbsupdown.png);
  background-repeat: no-repeat;
  background-position: 4px 0;
  background-clip: content-box;
  border: none;
}

button {
  position: relative;
}

.btnDown,
.btnUp {
  height: 50px;
  width: 50px;
  background-size: 80px;
}

.btnDown div,
.btnUp div {
  position: absolute;
  left: 19px;
  top: 60px;
}

.btnDown {
  background-image: url(https://i.ibb.co/H4MZMFT/thumbsupdown.png);
  background-repeat: no-repeat;
  background-position: -33px 0;
  background-clip: content-box;
  border: none;
}

.group {
  padding: 2px;
  height: 80px;
}

.book-title {
  font-size: 0.3em;
  font-family: arial;
  height: 59px;
  width: 50%;
  padding: 10px;
  display: table-cell;
  vertical-align: middle;
}

.img-cnt {
  width: 180px;
  height: 282px;
}

@media only screen and (min-device-width: 320px) and (max-device-width: 850px) {
  .flex-item {
    width: 470px;
    padding: 6px;
  }
  .img-cnt {
    width: 100%;
    height: auto;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='book-items'></div>

Upvotes: 0

Nadir Latif
Nadir Latif

Reputation: 3763

Well as I understand, the thumbsUp counter needs to be set to 0 when the thumbsDown button is clicked. The thumbsDown counter needs to be set to 0 when the thumbsUp button is clicked. This can be done by modifying the upClick and downClick buttons so they work as follows:

function upClick(idx) {
  GV_MOVIES[idx].thumbsUp++;
  GV_MOVIES[idx].thumbsDown = 0;
  display();
}

function downClick(idx) {
  GV_MOVIES[idx].thumbsDown++;
  GV_MOVIES[idx].thumbsUp = 0;
  display();
}

Upvotes: 1

Related Questions