2

Languages involved: HTML, CSS, JS

Context: I'm relatively new to web development. I have two elements overlapping each other. One is a slider, one is a div. The slider is on top of the div.

Code snippets:

<div id="myDiv">
  <input id="mySlider" type="range" min=1 max=100 step=1>
</div>

and

initListeners() {
  document.getElementById("myDiv").addEventListener("click", divFunction);
  document.getElementById("mySlider").addEventListener("input", sliderFunction);
}

I need to make it that when you click the slider, it doesn't click the div. How would I go about doing that? I've tried z-index, but that doesn't seem to change anything.

Thanks in advance!

Steichen
  • 69
  • 1
  • 1
  • 3
  • https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation –  Nov 14 '18 at 17:52

3 Answers3

1

As I'm sure you've figured out by now, events in JavaScript by default bubble up from a child to a parent. You need to stop that from happening at the child level, also known as preventing propagation.

Using the stopPropagation function, you can handle this as follows:

function sliderFunction(e) {
     e.stopPropagation();
}

Simple. That event will no longer reach the parent.

EDIT

While stop propagation is the correct method to use, event listeners must also match in type. Therefore, both the slider and the parent DIV must have click event listeners (instead of input and click). stopPropagation stops propagation of a specific type of event.

function divFunction() {
 console.log('DIV clicked!');
}

function sliderFunction(event) {
  event.stopPropagation();
 console.log('Slider clicked!');
}

function initListeners() { 
 document.getElementById('myDiv').addEventListener('click', divFunction);
  document.getElementById('mySlider').addEventListener('click', sliderFunction); 
} 

initListeners();
/* unnecessary visual aides */

body *:not(label) {
  padding: 2rem;
  outline: 1px solid red;
  position: relative;
}

label {
  display: inline-block;
  position: absolute;
  background: #222;
  color: #fff;
  top: 0; left: 0;
}
<div id="myDiv">
  <label>#myDiv</label>
  <div id="tools">
    <label>#tools</label>
    <input type="range" id="mySlider">
  </div>
</div>
sheng
  • 1,226
  • 8
  • 17
  • 1
    Thanks! I'll try that. – Steichen Nov 14 '18 at 17:55
  • Thanks :) Happy to be here! – Steichen Nov 14 '18 at 18:09
  • So it reaches and activates the div before the slider... What's the best way to make the slider be the first to react? – Steichen Nov 14 '18 at 23:07
  • @Steichen Apologies for the late reply. I'm not quite sure what you're having trouble with, if you're stopping propagation in the slide event listener, it won't reach the parent div unless the parent is directly clicked. If you link a code example I can help further. – sheng Nov 15 '18 at 06:30
  • Changing the code a bit to more accurately fit the situation.
    initListeners() { document.getElementById("myDiv").addEventListener("click", divFunction); document.getElementById("mySlider").addEventListener("input", sliderFunction); } The problem I'm having is when I go to click the slider, the div element is the one that picks it up. The slider does not get any interaction, as though the div is on top of the slider in order of propagation.
    – Steichen Nov 15 '18 at 17:26
  • @Steichen Oh boy, huge oversight on my part. You're capturing the wrong event on `#mySlider` -- `input` instead of `click`. An input event would get fired once the slider changes. [JSFiddle here.](https://jsfiddle.net/shengslogar/tgx5bmzf/25/) – sheng Nov 15 '18 at 18:07
  • Turns out it wasn't a propagation issue... I had the element in the wrong place. Turns out the order matters heavily. Thanks again! – Steichen Nov 16 '18 at 22:48
  • @Steichen Happy to help! If this or any other answer helped you solve your question, please mark it as accepted. Feel free to post your own solution as well. – sheng Nov 17 '18 at 17:51
0

You can also check the target once you fire that click event. I've used this approach before:

JSFiddle: http://jsfiddle.net/L4ck7ygo/1/

function divFunction(e) {
  if (e.target !== this) {
    return;
  } else {
    console.log('hit');
  }
}

When the fiddle first loads, click the slider and you'll see the console log out some text. To see it work, remove the line that is being pointed to and rerun the fiddle. Now when you click the slider, you won't see anything logged in the console, but if you click on the div and not the slider, it will log to the console.

function initListeners() {
  document.getElementById("myDiv").addEventListener("click", divFunction);
  document.getElementById("mySlider").addEventListener("input", sliderFunction);
}

initListeners();

function divFunction(e) {
  console.log('Firing...') // <-- This will log on any click
  if (e.target !== this) {
    return;
  } else {
    console.log('hit'); // <-- This will NOT log except for div click
  }
}

function sliderFunction() {
  console.log('Doing stuffs...');
}
<div id="myDiv">
  <input id="mySlider" type="range" min=1 max=100 step=1>
</div>
justDan
  • 2,302
  • 5
  • 20
  • 29
  • The problem I'm having is it registers to the div first and doesn't propagate down to the slider. I need it to check the slider first, then check the div. – Steichen Nov 14 '18 at 23:16
0

UPDATE: Stupidity on my part. I had the ordering wrong for the elements which caused propagation to not act as intended.

Steichen
  • 69
  • 1
  • 1
  • 3