skip to Main Content

I have the following situation:
My user presses and holds the left mouse button on element 1 and releases the mouse button on element 2. This emits a click on the wrapping element. This click should not happen, because the click on the wrapper executes another action, so i can not ignore the click completely on the wrapper.

Even when i use preventDefault or stopPropagation the click is emitted. See my example:

const wrapper = document.getElementById('wrapper');
const one = document.getElementById('one');
const two = document.getElementById('two');
const preventDefault = document.getElementById('preventDefault');
const stopPropagation = document.getElementById('stopPropagation');

const clear = document.getElementById('clear');
clear.addEventListener('click', () => console.clear());

const subscribe = (element) => {
  const eventHandler = (event) => {
    console.log(event.defaultPrevented ? 'prevented' : '', event.type, 'on', element.id);
    if (preventDefault.checked) {
      event.preventDefault();
    }
    if (stopPropagation.checked) {
      event.stopPropagation();
    }
  };
  element.addEventListener('mousedown', eventHandler);
  element.addEventListener('mouseup', eventHandler);
  element.addEventListener('click', eventHandler);
};

subscribe(wrapper);
subscribe(one);
subscribe(two);
.container {
  border: 1px solid gray;
  background-color: lightgray;
}

.toolbar {
  position: absolute;
  right: 1rem;
  top: 2rem;
  display: flex;
  flex-direction: column;
}

#wrapper {
  position: relative;
  width: 250px;
  height: 150px;
}

#one,
#two {
  position: absolute;
  width: 50px;
  height: 50px;
  background-color: blue;
  color: white;
}

#one {
  left: 50px;
  top: 50px;
}

#two {
  left: 150px;
  top: 50px;
}
Click an hold left mouse button on 1 and release it on 2. Always a click is emitted on wrapper.
<div class="container" id="wrapper">
  wrapper
  <div class="container" id="one">1</div>
  <div class="container" id="two">2</div>
</div>

<div class="toolbar">
  <button id="clear">clear</button>
  <label>
    <input type="checkbox" id='preventDefault'>
    preventDefault
  </label>
  <label>
    <input type="checkbox" id='stopPropagation'>
    stopPropagation
  </label>
</div>

2

Answers


  1. A click event is only emitted on elements if the mousedown and mouseup happened within this element. You are creating a mousedown on 1 and a mouseup on 2. The wrapper element on the other hand receives mousedown, mouseup and click

    Login or Signup to reply.
  2. You mentioned that you cannot completely ignore the click on the wrapper element, so I assume you want to perform different actions for clicks on element 1 and element 2 while still allowing some action to occur when a click happens on the wrapper. You can achieve this by checking which element was the target of the click in your click event handler.

    With this code, you can differentiate between clicks on element 1, element 2, and the wrapper and perform different actions as needed. The wrapper’s click event will still occur, but you can handle it separately inside the handleClick function.

     const wrapper = document.getElementById('wrapper');
     const one = document.getElementById('one');
     const two = document.getElementById('two');
     const preventDefault = 
     document.getElementById('preventDefault');
     const stopPropagation = document.getElementById('stopPropagation');
    
     const clear = document.getElementById('clear');
     clear.addEventListener('click', () => console.clear());
    
     let clickStartTime;
    
     wrapper.addEventListener('mousedown', () => {
       clickStartTime = new Date().getTime();
     });
    
     wrapper.addEventListener('mouseup', (event) => {
       const clickDuration = new Date().getTime() - clickStartTime;
       if (clickDuration < 100) {
         // It's a quick click (not a down-hold-and-release)
         console.log('Quick click on wrapper');
         if (preventDefault.checked) {
           event.preventDefault();
         }
         if (stopPropagation.checked) {
           event.stopPropagation();
         }
       } else {
         // Down-hold-and-release
         console.log('Down-hold-and-release on wrapper');
       }
     });
    
     one.addEventListener('click', (event) => {
       console.log('Clicked on one');
       if (preventDefault.checked) {
         event.preventDefault();
       }
       if (stopPropagation.checked) {
         event.stopPropagation();
       }
     });
    
     two.addEventListener('click', (event) => {
       console.log('Clicked on two');
       if (preventDefault.checked) {
         event.preventDefault();
       }
       if (stopPropagation.checked) {
         event.stopPropagation();
       }
     });
    .container {
      border: 1px solid gray;
      background-color: lightgray;
    }
    
    .toolbar {
      position: absolute;
      right: 1rem;
      top: 2rem;
      display: flex;
      flex-direction: column;
    }
    
    #wrapper {
      position: relative;
      width: 250px;
      height: 150px;
    }
    
    #one,
    #two {
      position: absolute;
      width: 50px;
      height: 50px;
      background-color: blue;
      color: white;
    }
    
    #one {
      left: 50px;
      top: 50px;
    }
    
    #two {
      left: 150px;
      top: 50px;
    }
    Click an hold left mouse button on 1 and release it on 2. Always a click is emitted on wrapper.
    <div class="container" id="wrapper">
      wrapper
      <div class="container" id="one">1</div>
      <div class="container" id="two">2</div>
    </div>
    
    <div class="toolbar">
      <button id="clear">clear</button>
      <label>
        <input type="checkbox" id='preventDefault'>
        preventDefault
      </label>
      <label>
        <input type="checkbox" id='stopPropagation'>
        stopPropagation
      </label>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search