jhine
jhine

Reputation: 247

Prevent button with click event inside div with mouseover event

I have a div with a mouseenter event. Within that div there is a button with a click event. The idea is that the user hovers over the div, on the mouseenter event, the div becomes "active". If the div is active, then the button is visible and clickable.

Everything seems to work great on desktop. However, on mobile, due to the mouseenter event, if you click where the button should become visible, on an inactive div, the button is clicked.

I'd like to prevent the user from accidentally clicking the button when they think they're clicking the div to make it "active". I'm assuming this can be done with event handling https://v2.vuejs.org/v2/guide/events.html#Event-Modifiers but I cannot for the life of me work it out.

Please see the following codepen - https://codepen.io/jameshine/pen/GRNNzdq or code below.

Please note: If you test on desktop and click the button, you will still get the "clicked by mistake" error message. This codepen is for mobile view, but I'm unsure I can force it to display my problem in mobile?

<div id="app">
  <div class="container mx-auto">
    <div class="flex -mx-2">
      <div class="w-1/2 px-2" @mouseenter="activate(key)" v-for="(item, key) in items" :key="key">
        <div class="h-full p-5 rounded-lg" :class="[ active === key ? 'bg-yellow-500' : 'bg-gray-300']">
          <div class="mb-10">
            <p>{{ item.name }}</p>
          </div>

          <button class="bg-red-500 px-3 py-2 rounded" @click="alert('I\'ve been clicked by mistake')" v-if="active === key">Activate Me</button>
        </div>
      </div>
    </div>
  </div>
</div>
new Vue({
  el: "#app",

  data() {
    return {
      active: undefined,
      items: [
        {
          name: "A"
        },
        {
          name: "B"
        }
      ]
    };
  },
  methods: {
    activate(key) {
      this.active = key;
    }
  }
});

Upvotes: 0

Views: 341

Answers (1)

Hannah
Hannah

Reputation: 1143

If I understand your question correctly, it sounds like you need to do something like this:

<button @click.prevent.stop="handleClick(key)">Activate me</button>

// Methods:
handleClick(key) {
  if (this.active !== key) {
    this.active = key;
  } else {
    // Do whatever the button should do here
  }
}

UPDATE 1:

The issue seems to be with the mouseenter event firing immediately before the click event on mobile. This seems a bit hacky but I think it should work - if you had a slight delay inside your activate method, like this:

activate(key) {
  setTimeout(() => this.active = key, 50);
}

UPDATE 2:

Here's an alternative solution - add this to your parent div:

@touchstart.prevent="handleTouchStart($event, key)"

Then in your methods:

handleTouchStart($event, key) {
  if (this.active === key) {
    $event.target.click();
  } else {
    this.active = key;
  }
}

What this does is, when a touchStart event is registered on the parent div, if it is not currently "active", the event is cancelled but the div is made active. If it is currently active, it allows the click event to proceed as normal.

Upvotes: 1

Related Questions