skip to Main Content

There is a thumb-up button on each message bubble of the chatbot. As there are multiple bubbles on each page, both the text bubble and the thumb-up button are indexed. I am attempting to store the results of all the thumb-up buttons in a dictionary. However, this function only saves the last thumb-up value. I am curious why this is happening.

let clickedThumbUP = false;
let rating_dict = { "ratingUp": {}};

//for each click, we store the button id and click response to a dictionary, then we push the entire dictionary to the database? 
let rating_up = $(".thumbup").click(function(){
  
  //let rating_up  = checkRating(clickedThumbUP);
  clickedThumbUP = !clickedThumbUP; // Toggle state on each click

  // get button id
  buttonid = $(this).data("index")

  if (clickedThumbUP === true) {
        $(this).toggleClass("thumbup thumb-up-black");

        //store result in dictionary
         rating_dict['ratingUp'][buttonid] = true;
        //user can't press the thumbdown button

          return true
        }
      
      else{

        $(this).toggleClass("thumbup thumb-up-black");

        //for (let item of Object.entries(rating_dict['ratingUp'])){
          rating_dict['ratingUp'][buttonid] = false;
        //}

        return false

      
    }
  

  });

html

<div class="msg ${side}-msg">
  <div class="msg-img" style="background-image: url(${img})"></div>
  <div class="ratings">
    
 
  <div class="msg-bubble">
    <div class="rating-img">
    <button type="submit" class="thumbup" data-index="${message_index}""></button>
    <button type="submit" class="thumbDown" id="thumbDown-${message_index}"></button>
    </div>

  </div>
    <div class="msg-text">${text}</div>  
</div>

</div>
</div>

2

Answers


  1. As you want each of your thumbs-up buttons to have its own true/false state, maintaining one global variable clickedThumbUP to track if the value is true/false isn’t going to do that for you, as clicking on one thumbs-up button and then a different one will change this single global variable value. Instead, check if your thumbs-up button index is already in your rating_dict object, and use that to determine if your thumbs-up button is active or not for the message:

    const rating_dict = {"ratingUp": {}};
    
    const rating_up = $(".thumbup").click(function() {
      // get button id
      const buttonid = $(this).data("index");
      const isActive = Boolean(rating_dict.ratingUp[buttonId]);
      $(this).toggleClass("thumbup thumb-up-black"); // we toggle this class regardless of which branch we take below, so we can move it up here instead of repeating it twice 
      if (isActive) { // if it's active, make it inactive
        $(this).toggleClass("thumbup thumb-up-black");
        rating_dict.ratingUp[buttonid] = false;
        return false
      } else {
        rating_dict.ratingUp[buttonid] = true;
        return true
      }
    });
    

    This can be refactored further by removing the if-statement, and instead negating the current buttonid value and updating the object accordingly. This works because if your button isn’t in the object, you’ll get undefined, which when negated using ! becomes true:

    const rating_dict = {"ratingUp": {}};
    
    const rating_up = $(".thumbup").click(function() {
      const buttonid = $(this).data("index");
      $(this).toggleClass("thumbup thumb-up-black");
    
      rating_dict.ratingUp[buttonId] = !rating_dict.ratingUp[buttonId];
      return rating_dict.ratingUp[buttonId];
    });
    

    Notes:

    • .click() is deprecated in jQuery, instead, use .on("click", function { ... })
    • Using return true or return false in .click() or .on() impacts if you prevent the default behavior of what you’re clicking on. It also stops the event from "bubbling" up the DOM to the parent elements. You typically want this to be consistent each time you click, so it’s a bit strange that you sometimes return false and other times return true. If you don’t need it, remove the return in your event handler callback.
    • If you’re not doing anything with jQuery object that’s being stored in the rating_up variable you can remove it, and just use $(".thumup").on("click", ...) without assigning it to anything.
    • Most of your jQuery code can be replaced with vanilla JS:
      • .click() can be replaced with .addEventListener("click", function(e) {...}). You will need to get your elements using .querySelectorAll() and then iterate your elements and add the event listener to each, or use event-delegation if you use this option.
      • $(this).data("index") can be replaced with this.dataset.index
      • $(this).toggleClass(...) can be replaced with this.classList.toggle(...)
    Login or Signup to reply.
  2. The problem is that you’re using a global clickedThumbUP variable to manage the state of all the thumb-up buttons. Instead you need have a place to store the state of each button.

    One place to store the state for each button element would be on a custom data attribute for each button:

    let rating_dict = { "ratingUp": {} };
    let thumbUpButtons = document.querySelectorAll('.thumbup');
    thumbUpButtons.forEach(function(button) {
      button.addEventListener('click', function(event) {
        let buttonid = event.currentTarget.getAttribute('data-index');
        let clickedThumbUP = event.currentTarget.getAttribute('data-clicked') === 'true';
        clickedThumbUP = !clickedThumbUP;
    
        // Update data-clicked attribute with new state
        event.currentTarget.setAttribute('data-clicked', clickedThumbUP);
    
        if (clickedThumbUP) {
          event.currentTarget.classList.add('thumb-up-black');
          event.currentTarget.classList.remove('thumbup');
        } else {
          event.currentTarget.classList.add('thumbup');
          event.currentTarget.classList.remove('thumb-up-black');
        }
        rating_dict['ratingUp'][buttonid] = clickedThumbUP;
        console.log(rating_dict);
      });
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search