Mouse and click events on three buttons

Viewed 88

Let's say that I have the following three buttons in a div on a page:

<div class="action_buttons">
    <button class="btn btn-sm btn-outline-primary add_to_cart">Add to Cart</button>
    <button style="display:none;" class="btn btn-sm text-success added"><i class="fas fa-fw fa-check"></i> Added</button>
    <button style="display:none;" class="btn btn-sm text-danger remove"><i class="fas fa-fw fa-times"></i> Remove</button>
</div>

What I'm tying to achieve is the following:

  1. When button with class add_to_cart is clicked, hide it and show button with class added
  2. When button with class added is hovered on, hide it and show button with class remove
  3. When button with class remove is hovered on, hide it and show back the button with class added
  4. When button with class remove is clicked, hide it and show back button with class add_to_cart

So far this is the code I have:

$(document).on('click', '.add_to_cart', function(e){
    e.preventDefault();

    $(this).hide();
    $(this).closest('div').find('.added').show();
});

$(document).on('mouseenter', '.added', function(e){
    $(this).hide();
    $(this).closest('div').find('.remove').show();
});

$(document).on('mouseleave', '.remove', function(e){
    $(this).hide();
    $(this).closest('div').find('.added').show();
});

$(document).on('click', '.remove', function(e){
    e.preventDefault();

    $(this).hide();
    $(this).closest('div').find('.add_to_cart').show();
});

The issue that I have with this code is that when I click on Remove, because there is a mouseleave event on that button that shows the button with class added, that button is still visible after I click remove. I want only the button with class add_to_cart to be visible when I click remove.

Thanks in advance for any help.

5 Answers

Little tricky , but you can fix it by using a var that check if remove was clicked or not , if clicked return without executing mouseleave event function content

See below snippet :

var removeClicked = false;

$(document).on('click', '.add_to_cart', function(e) {
  e.preventDefault();

  $(this).hide();
  $(this).closest('div').find('.added').show();
});

$(document).on('mouseenter', '.added', function(e) {
  $(this).hide();
  $(this).closest('div').find('.remove').show();
});

$(document).on('mouseleave', '.remove', function(e) {
  if(removeClicked)  {
    // reset click 
    removeClicked = false
    return;
  }
  $(this).hide();
  $(this).closest('div').find('.added').show();
});

$(document).on('click', '.remove', function(e) {
  e.preventDefault();
  removeClicked =true;
  $(this).hide();
  $(this).closest('div').find('.add_to_cart').show();
  $(this).parent('div').find('.added').hide();
});
.hide {
  display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>


<div class="action_buttons">
  <button class="btn btn-sm btn-outline-primary add_to_cart">Add to Cart</button>
  <button class="btn btn-sm text-success added hide"><i class="fas fa-fw fa-check"></i> Added</button>
  <button class="btn btn-sm text-danger remove hide"><i class="fas fa-fw fa-times"></i> Remove</button>
</div>

<div class="action_buttons">
  <button class="btn btn-sm btn-outline-primary add_to_cart">Add to Cart</button>
  <button class="btn btn-sm text-success added hide"><i class="fas fa-fw fa-check"></i> Added</button>
  <button class="btn btn-sm text-danger remove hide"><i class="fas fa-fw fa-times"></i> Remove</button>
</div>

Try to separate logic and style as good as possible. Changing inline-styles with javascript is always getting hard to maintain. Try to use CSS for style related things. You can solve it with CSS and just add and remove one single attribute ...

$(document).on('click', '.add_to_cart', function(e){
    e.preventDefault();
    $(this).closest('div').attr('data-js-added', 'true');
});

$(document).on('click', '.remove', function(e){
    e.preventDefault();
    $(this).closest('div').removeAttr('data-js-added');
});
.added,
.remove,
[data-js-added="true"] .add_to_cart,
[data-js-added="true"]:hover .added {
   display: none;
}

[data-js-added="true"] .added,
[data-js-added="true"]:hover .remove {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="action_buttons">
    <button class="btn btn-sm btn-outline-primary add_to_cart">Add to Cart</button>
    <button class="btn btn-sm text-success added"><i class="fas fa-fw fa-check"></i> Added</button>
    <button class="btn btn-sm text-danger remove"><i class="fas fa-fw fa-times"></i> Remove</button>
</div>

You can add some flag(data-attribute) to your button this will help you to delete button and remove that attribute whenever necessary.

Demo Code :

$(document).on('click', '.add_to_cart', function(e) {
  e.preventDefault();
  $('.remove').attr('clicked', ''); //remove attr 
  $(this).hide();
  $(this).closest('div').find('.added').show();
});

$(document).on('mouseenter', '.added', function(e) {
  $(this).hide();
  $(this).closest('div').find('.remove').show();
});

$(document).on('mouseleave click', '.remove', function(e) {
  if (e.type === "mouseleave") {
    //will not go inside unless attr is yes
    if ($(this).attr('clicked') != 'yes') {
      $(".element", this).hide();
      $(this).hide();
      $(this).closest('div').find('.added').show();
    }
  } else if (e.type === "click") {
    console.log("i am in")
    $(this).attr('clicked', 'yes'); //added attr
    $(this).hide();
    $(this).closest('div').find('.add_to_cart').show();
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="action_buttons">
  <div class="action_buttons">
    <button class="btn btn-sm btn-outline-primary add_to_cart">Add to Cart</button>
    <button style="display:none;" class="btn btn-sm text-success added"><i class="fas fa-fw fa-check"></i> Added</button>
    <button style="display:none;" class="btn btn-sm text-danger remove"><i class="fas fa-fw fa-times"></i> Remove</button>
  </div>

You are just missing one condition on mouseleave of .remove element. Check if .add_to_cart is hidden then only show the .added element.

See the Snippet below:

$(document).on('click', '.add_to_cart', function(e){
    e.preventDefault();

    $(this).hide();
    $(this).closest('div').find('.added').show();
});

$(document).on('mouseenter', '.added', function(e){
    $(this).hide();
    $(this).closest('div').find('.remove').show();
});

$(document).on('mouseleave', '.remove', function(e){
    $(this).hide();
    /* ADD below condition to show the .add element */
    if($(this).closest('div').find('.add_to_cart').is(":hidden")){
      $(this).closest('div').find('.added').show();
    }
});

$(document).on('click', '.remove', function(e){
    e.preventDefault();

    $(this).hide();
    $(this).closest('div').find('.add_to_cart').show();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="action_buttons">
    <button class="btn btn-sm btn-outline-primary add_to_cart">Add to Cart</button>
    <button style="display:none;" class="btn btn-sm text-success added"><i class="fas fa-fw fa-check"></i> Added</button>
    <button style="display:none;" class="btn btn-sm text-danger remove"><i class="fas fa-fw fa-times"></i> Remove</button>
</div>

Suggestion: This could also be just one button.

Depending on the event and the current "state" of the button (the classses it has), it makes only four conditions and only one event handler is needed.

I think the code is easier to read and maintain.

let buttonContent = [
  "Add to Cart",
  "<i class='fas fa-fw fa-check'></i> Added",
  "<i class='fas fa-fw fa-times'></i> Remove"
];

$(document).on("click mouseenter mouseleave", ".action_buttons .btn",
  function(event) {

    let $this = $(this)

    // CONDITIONS
    // Click "Add to cart"
    if (event.type === "click" && $this.is(".add_to_cart")) {
      $this.addClass("text-success added");
      $this.removeClass("btn-outline-primary add_to_cart");
      $this.html(buttonContent[1]);
      return;
    }

    // Click "Remove"
    if (event.type === "click" && $this.is(".remove")) {
      $this.removeClass("text-success added text-danger remove");
      $this.addClass("btn-outline-primary add_to_cart");
      $this.html(buttonContent[0]);
      return;
    }

    // Mouse enter
    if (event.type === "mouseenter" && $this.is(".added")) {
      $this.toggleClass("text-success added text-danger remove");
      $this.html(buttonContent[2]);
      return;
    }

    // Mouse leave
    if (event.type === "mouseleave" && $this.is(".remove")) {
      $this.toggleClass("text-success added text-danger remove");
      $this.html(buttonContent[1]);
    }
  }
);
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>

<div class="action_buttons">
  <button class="btn btn-sm btn-outline-primary add_to_cart">Add to Cart</button>
</div>

Related