querySelector event listener `scroll` - javascript

I am trying to understand why scroll event listener of querySelector element doesn't work here
document.querySelector('.test-scroll')
.addEventListener('scroll', function() {
alert('Scroll');
}, false);
.test-scroll {
height: 2000px;
overflow-x: none;
overflow-y: scroll;
border: 1px solid #000;
}
<div class="test-scroll"> </div>

Because there is no content force it to actually scroll anything.
Here I added an inner div, which is higher, and make it scrollable.
Stack snippet
document.querySelector('.test-scroll')
.addEventListener('scroll', function() {
alert('Scroll');
}, false);
.test-scroll {
height: 2000px;
overflow-x: none;
overflow-y: scroll;
border: 1px solid #000;
}
.test-scroll div {
height: 3000px;
background: red;
}
<div class="test-scroll">
<div></div>
</div>

Related

How can I add a scrollbar to a div that has a parent div with overflow hidden?

I have am restricting the body to be the viewport's height and setting overflow: hidden on it. I am using jQuery to slide in a div that is absolutely positioned outside of the viewable area. The div that slides in is larger than the viewport and I would like for its contents to be scrollable within the viewport window.
Here's my fiddle: https://jsfiddle.net/hvew0qx4/1/
HTML:
<div class='buttons'>
<button id="toggle-results">Show Results</button>
</div>
<div class="map general-styling"></div>
<div id="results-area" class='movable'>
<div class="results general-styling"></div>
</div>
CSS:
body {
height: 100vh;
overflow: hidden;
position: relative;
}
.general-styling {
box-sizing: border-box;
width: 100%;
border-width: 10px;
border-style: solid;
}
.movable {
transition: all 0.3s ease;
position: absolute;
z-index: 44;
width: 100vw;
min-height: 100vh;
background-color: white;
overflow-y: scroll;
}
.map {
background-color: red;
border-color: pink;
height: 100vh;
}
.results {
background-color: blue;
border-color: orange;
height: 1000px;
}
.buttons {
position: absolute;
z-index: 1000;
top: 40px;
right: 40px;
}
JavaScript:
var $toggleResultsBtn = $('#toggle-results');
var $resultsArea = $('#results-area');
var $body = $('body');
$('.movable').css('top', $body.height());
$toggleResultsBtn.on('click', function(){
$toggleResultsBtn.text(function(i, text){
return text === "Show Results" ? "Hide Results" : "Show Results";
});
$resultsArea.css('top', function(i, value){
return value === '0px' ? $body.height() : '0px';
});
});
Set the height of the inner div to that of its container, and then add the property overflow-y: scroll to it.
Like so:
.container {
height: 200px;
overflow: hidden;
}
.elem {
height: 200px;
overflow-y: scroll;
}
If you want the div to scroll down at least 1000px (you want a scrollbar without any content in your div), you may want the outer div to have overflow-y set to scroll, like so:
.container {
height: 200px;
overflow-y: scroll;
}
.elem {
height: 1000px;
}
EDIT: I played around with your fiddle, and it looks like the biggest thing holding you back from what you are looking for is that you are using min-height for your .moveable div.
Change it to:
.movable {
transition: all 0.3s ease;
position: absolute;
z-index: 44;
width: 100vw;
height: 100vh; /* Change was made on this line */
background-color: white;
overflow-y: scroll;
}
min-height allows your div to grow. You clearly don't want that here, since if the div can grow, there is no need for scrolling.
EDIT 2: Added bonus - to get the scrollbar back from the edge of the screen, override the default margin given to the body:
body {
margin: 0;
}
EDIT 3: Here's an updated JSFiddle: https://jsfiddle.net/anishgoyal/hvew0qx4/4/

Allow pointer (click) events to pass through element whilst maintaining scroll facility

My goal is to have an element which allows:
elements underneath to be clicked on/interacted with,
scrolling
The solution to 1 is widely known to be pointer-events: none. This is as described in Click through a DIV to underlying elements.
However, the element can not be scrolled, because the scroll bar appears on the element with pointer-events: none. This can be seen in this example: http://jsbin.com/madure/2/edit?html,css,output.
Is there a workaround to this, or is it something that would need to be addressed at the browser level? Perhaps with an additional rule, pointer-events: scrollOnly.
The pointer-events CSS property specifies under what circumstances (if
any) a particular graphic element can become the target of mouse
events.
So basically if you make the upper layer insensitive for click it will be so for wheel events too. I suggest on of two things
JavaScript workaround:
Which basically use the fact that:
Note that preventing an element from being the target of mouse events
by using pointer-events does not necessarily mean that mouse event
listeners on that element cannot or will not be triggered
$(function(){
$("#stage-layer").on("wheel",function(e){
eo=e.originalEvent;
s=$("#scrollable")
switch(eo.deltaMode){
case 0: //DOM_DELTA_PIXEL Chrome
s.scrollTop(eo.deltaY+s.scrollTop())
s.scrollLeft(eo.deltaX+s.scrollLeft())
break;
case 1: //DOM_DELTA_LINE Firefox
s.scrollTop(15*eo.deltaY+s.scrollTop()) //scroll(e.deltaX, e.deltaY); Just a random small amount of scrolling
s.scrollLeft(15*eo.deltaX+s.scrollLeft())
break;
case 2: //DOM_DELTA_PAGE
s.scrollTop(0.03*eo.deltaY+s.scrollTop())
s.scrollLeft(0.03*eo.deltaX+s.scrollLeft())
break;
}
e.stopPropagation();
e.preventDefault()
})
})
.container {
position: relative;
width: 400px;
height: 400px;
border: 2px solid black;
}
#stage-layer {
position: absolute;
width: 100%;
box-sizing: border-box;
height: 100%;
border: 2px solid yellow;
}
#application-layer {
position: relative;
box-sizing: border-box;
height: 100%;
border: 2px solid pink;
pointer-events: none;
}
rect:hover {
fill: blue;
}
#scrollable {
overflow: auto;
color: hotpink;
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<svg id="stage-layer">
<rect width="200" height="200"></rect>
</svg>
<div id="application-layer">
<div id="scrollable">
<p>foo1</p>
<p>foo2</p>
<p>foo3</p>
<p>foo4</p>
<p>foo5</p>
<p>foo6</p>
</div>
</div>
</div>
A nice tip:
This will not probably yield an immediate solution but it is a good choice for long term web development :
We would like
to provide finer grained control (than just auto and none) in HTML ...
if you have any particular things that you would like to be able to do
with this property, then please add them to the Use Cases section of
this wiki page (don't worry about keeping it tidy).
Source : pointer-events
Translated #user10089632's answer to vanilla javascript
function scroller(event){
scrollable=document.getElementById("scrollable");
switch(event.deltaMode){
case 0: //DOM_DELTA_PIXEL Chrome
scrollable.scrollTop+=event.deltaY
scrollable.scrollLeft+=event.deltaX
break;
case 1: //DOM_DELTA_LINE Firefox
scrollable.scrollTop+=15*event.deltaY
scrollable.scrollLeft+=15*event.deltaX
break;
case 2: //DOM_DELTA_PAGE
scrollable.scrollTop+=0.03*event.deltaY
scrollable.scrollLeft+=0.03*event.deltaX
break;
}
event.stopPropagation();
event.preventDefault()
}
document.onwheel = scroller;
.container {
position: relative;
width: 400px;
height: 400px;
border: 2px solid black;
}
#stage-layer {
position: absolute;
width: 100%;
box-sizing: border-box;
height: 100%;
border: 2px solid yellow;
}
#application-layer {
position: relative;
box-sizing: border-box;
height: 100%;
border: 2px solid pink;
pointer-events: none;
}
rect:hover {
fill: blue;
}
#scrollable {
overflow: auto;
color: hotpink;
height: 100px;
}
<div class="container">
<svg id="stage-layer">
<rect width="200" height="200"></rect>
</svg>
<div id="application-layer">
<div id="scrollable">
<p>foo1</p>
<p>foo2</p>
<p>foo3</p>
<p>foo4</p>
<p>foo5</p>
<p>foo6</p>
</div>
</div>
</div>

How can i get 2 classes by id inside the same function

I need to target two div elements and toggle their classes simultanouesly.
I understand that I can get multiple divs "by ID" by using .querySelectorAll
but when I get to .classlist.toggle ("NewClassName"); how can I target two classes??
So here's some code:
#small-div{
background-color:#aaaaaa;
border: 3px solid #aaaaaa;
padding: 0px 0px 0px 0px;
margin: auto 10px auto auto;
border-radius: 10px;
overflow: auto;
}
.tobetoggled{
width: 45%;
float: left;
}
#small-div2{
background-color:#aaaaaa;
border: 3px solid #aaaaaa;
padding: 0px 0px 0px 0px;
margin: auto 10px auto auto;
border-radius: 10px;
overflow: auto;
}
.tobetoggled2{
width: 45%;
float: right;
}
.toggletothis{
width: 100%;
float: left;
position: fixed;
display: block;
z-index: 100;
}
.toggletothis2{
width: 100%;
float: left;
position: fixed;
display: block;
z-index: 100;
}
.whensmalldivistoggled{
display: none;
}/* when small-div is clicked, small-div toggles to class "tobetoggled" while small-div 2 simultaneously toggles to class "whensmalldivistoggled" (the display none class) */
<div id="container">
<div class="tobetoggled" onclick="function()" id="small-div">
</div>
<div class="tobetoggled2" onclick="separatefunction()" id="small-div2">
</div>
</div> <!-- end container -->
<script>
function picClicktwo() {
document.querySelectorAll("small-div, small-div2").classList.toggle("toggletothis, whensmalldivistoggled");
}
</script>
So as you can see one div is on the right, the other is on the left, each set to 45% width. So if I toggle one div to 100% width the browser still respects the other divs space instead of taking the whole 100%.
So I'm thinking if I can get the div on the right ,for example, to not display when the div on the left is toggled, it will be out of the way so the left div can take all 100%
Maybe im going about this the wrong way. Any help is welcome. Thanks.
You can create a single javascript function that sets appropriate classes on each element. Since you have only two elements it is not too complex.
HTML
<div id="container">
<div id="lefty" onclick="toggle('lefty', 'righty')">Lefty</div>
<div id="righty" onclick="toggle('righty', 'lefty')">Righty</div>
</div>
JS
function toggle(target, other)
{
var t = document.getElementById(target);
var o = document.getElementById(other);
if (!t.className || t.className == "inative")
{
t.className = "active";
o.className = "inactive";
}
else
{
t.className = "";
o.className = "";
}
}
CSS
#container {
background-color: lightgreen;
padding: 15px 0;
}
#container div {
color: white;
width: 45%;
display: inline-block;
}
#lefty {
background-color: blue;
}
#righty {
background-color: purple;
}
#container div.active {
width: 90%;
}
#container div.inactive {
display:none;
}
https://jsfiddle.net/dLbu9odf/1/
This could be made more elegant or capable of handling more elements with something like toggle(this) and then some DOM traversal and iteration in javascript, but that's a bit beyond scope. If that were the case I would recommend jQuery.

Chrome 49 causing scroll when draggable element over scrollbar

This is a change in Chrome 49 from previous versions. In 49, if I have a draggable element, when I drag it over a vertical scrollbar it causes the horizontal scrollbar to scroll to the right, even when it's not accepted.
$(document).ready(function() {
$("#dragItem").bind("dragstart", function(e) {
e.originalEvent.dataTransfer.setData("Text", 'data');
});
});
#dropContainer {
border: 1px solid black;
overflow-x: auto;
overflow-y: auto;
width: 250px;
height: 250px;
display: inline-block;
}
#bigContent {
width: 1000px;
height: 1000px;
}
#dragSourceContainer {
display: inline-block;
vertical-align: top;
margin-top: 20px;
}
#dragItem {
border: 1px solid black;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="dropContainer">
<div id="bigContent">
</div>
</div>
<div id="dragSourceContainer">
<div id="dragItem" draggable="true">
drag me to the left, over top the vertical scrollbar
</div>
</div>
JS Fiddle:
https://jsfiddle.net/a1qnbkeb/
My question is: how can I stop this behaviour without doing some crazy temporary scroll binding? The reason I ask this is because inside "dropContainer", I do allow things also to be dragged, and if they are dragged "within" drop container, I do want this behaviour.
I just don't want it when they're dragging new things in from outside.

How to make block draggable within a certain block only?

I have a small problem. I pasted my code here.
My problem is this: I want to make my window div (<div id="window"> Drag me </div>) draggable only within warp div.
HTML code:
<div id="warp">
<div id="window">
Drag me
</div>
</div>
CSS code:
body {
margin: 0;
background-color: #e67e22;
}
#window {
width: 150px;
height: 200px;
//background-color: #1abc9c;
border: 2px solid #16a085;
padding: 20px;
}
#warp {
margin: 10px;
width: 700px;
height: 600px;
border: 2px solid #e74c3c;
}
JS code:
$(document).ready(function() {
$("#window").draggable();
});
I mean when I drag it with mouse then it shouldn't go out of warp div.
you can use
$( "#window" ).draggable({
containment: 'parent'
});
$("#window").draggable ({
containment : "#warp"
});

Categories

Resources