0

Is it possible to stop event propagation without preventing the default event behaviour?

This should let the input increment/decrement when scrolled but stop it from bubbling to any other elements and scrolling the outer div. (The following is Chrome-only, I think)

$("input[type=number]").on("mousewheel",function(e){ // only works with chrome I think
  e.stopPropagation();
  console.log("scrolled");
});
div{
  height:50px;
  overflow:auto;
  border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div>
  <input type='number'>
  <div class='filler'></div>
</div>

But the stopPropagation call seemingly does nothing. The outer div still scrolls.

Now, this particular issue (scrolling a number input) can be solved by preventingDefault and manually incrementing and decrementing the input (JSFiddle).

I'm looking for a general solution that doesn't involve re-creating the default behaviour.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
DanielST
  • 13,783
  • 7
  • 42
  • 65
  • You can't prevent scrolling ? – adeneo Feb 23 '15 at 17:08
  • 1
    Your title and your question are opposites. Which do you want to do: prevent default without stopping event propagation, or stop event propagation without preventing default? – user229044 Feb 23 '15 at 17:09
  • @adeneo ohreally? `document.body.addEventListener('mousewheel', function (e) {e.preventDefault();})` – Paul S. Feb 23 '15 at 17:10
  • @meagar oops, corrected. – DanielST Feb 23 '15 at 17:11
  • I like this question, however I don't think you have an alternative then to cancel out the mousewheel using preventDefault. IE only fires mousewheel when the cursor is over the element, focused or not. – Mouser Feb 23 '15 at 17:13
  • @adeneo my problem is that `stopPropagation` doesn't stop scrolling on the outer div. I want to keep defaultBehaviour without scrolling the outer div. – DanielST Feb 23 '15 at 17:14
  • @PaulS. - Yes, really, that stops the mousewheel, I can still scroll with arrow keys. – adeneo Feb 23 '15 at 17:59

2 Answers2

2

One possible workaround is to temporarily fix the input while mouse is over it:

$("input[type=number]").on("mousewheel",function(e){ 
    e.stopPropagation();
}).on("mouseenter", function() {
    $(this).css("position", "fixed");
}).on("mouseleave", function() {
    $(this).css("position", "");
});
div{
  height:50px;
  overflow:auto;
  border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div>
  <input type='number'>
  <div class='filler'></div>
</div>
georg
  • 211,518
  • 52
  • 313
  • 390
  • Well, this meets the criteria. I don't _love_ using mouseenter events for this kind of thing but this is the least hacky method I've seen. – DanielST Feb 23 '15 at 17:39
  • @slicedtoad: yes, this is not ideal, maybe focus/blur would be more appropriate. – georg Feb 23 '15 at 17:44
0

So the preventDefault alternative is I my opinion the only one that will make this work.

I've thought of this alternative, but is basically the same. It sets the wheel event on the div and cancels it when the input is detected.

$("body > div").on("mousewheel",function(e){
    if (e.target && e.target.tagName == "INPUT")
        {

        var currentVal = $(e.target).val() === "" ? 0:parseInt($(e.target).val(),10);
        var step = $(e.target).attr("step") || 1;
        //should have some min/max handling to be complete
        if(e.originalEvent.wheelDelta > 0){
            $(e.target).val(currentVal+parseInt(step,10));
        }else{
            $(e.target).val(currentVal-parseInt(step,10));
        }
            e.preventDefault();
    }
});

http://jsfiddle.net/jgsp1ory/5/

Mouser
  • 13,132
  • 3
  • 28
  • 54