How do I detect the mouse scroll button down event using ReactJS? - javascript

I'm having trouble understanding how to detect "mouse3" / the mouse scroll button down event using react's onMouseDown event.
I'm using onMouseDown on some element:
<Menu.Item
icon={<DashboardOutlined style={{ fontSize: '21px' }} />}
onClick={onClickDash}
onMouseDown={handleEvent}
>
Dashboard
</Menu.Item>
And then the handleEvent:
const handleEvent = (event) => {
if (event.type === 'mousedown') {
console.log('MOUSE DOWN', event);
} else {
console.log('MOUSE UP', event);
}
};
Problem is, I can't find a way of detecting the mouse scroll button down specifically. How can I detect that? The official mozilla docs don't provide an example either.

Disclaimer - At time of writing I was only targeting Chrome browser.
When a user scrolls a DOM scroll event is fired, an event which is built into ever browser by default. React has it’s own method, onScroll, which can be called on any component when the scroll event is fired. Using this onScroll method we can call a function as a result of a user scrolling.
Example;
<SomeComponent onScroll={someMeothod} />
As with any DOM event, an event object is created with properties that can provide useful information about the event and the element said event is related too. A scroll event is fired for every pixel a user scrolls. In this case, we are only concerned with identifying when the user has scrolled to the end of the parent element containing our content.
Calculating when user has scrolled to end of a container
Add an onScroll method to element containing content which calls a function on the components class:
<div className="content-container" onScroll={this.handleScroll}>
// Your content
</div>
Then create the handleScroll function to handle the scroll event:
class MyComponent extends React.Component {
handleScroll = e => {
let element = e.target
if (element.scrollHeight - element.scrollTop === element.clientHeight) {
// do something at end of scroll
}
}
render() {
return (
<div className="content-container" onScroll={this.handleScroll}>
// Your content
</div>
)
}
}
Let’s break down what is happening in the handleScroll method to make things a bit clearer…
e - this corresponds to the event itself. It is an object that is created by the browser with properties related to the scroll event we are working with.
let element = e.target - this allows us to find the element which dispatched the event using (e.target) and assign it to the variable which we can use in the rest of the code.
Now we (our code) knows which element is being scrolled and we have assigned it to a variable in our methods scope, we can access the properties of that element given by the browser and calculate if the user has scrolled to the end.
element.scrollHeight - this is the height in pixels of the elements content, including content not visible on the screen due to css overflow.
element.scrollTop - the height in pixels that an element's content is scrolled vertically.
element.clientHeight - the height in pixels of the scrollable part of the element.
Using the above properties, we can calculate if the user has scrolled to the bottom of the element by comparing the negative sum of the scrollHeight and scrollTop to the clientHeight. If they are are the same, the user has scrolled to the bottom of the element. By wrapping this in an if statement we can therefore ensure that our function within the if statement’s scope is only run when the user has scrolled to the end of the div and our if condition is met.

Related

angular event firing on wrong element

Question:
I have a container with a bound (wheel) event listener containing some headings and paragraphs just for demo purposes. When I use the mouse wheel to scroll, the scroll event is occurring on one of the inner elements rather than on the container having the bound event.
Why is an event firing on a child element of a container rather than on the bound element itself?
Background:
I am playing around with angular on StackBlitz and wanted to implement an event listener on a <div> container to handle the scroll event:
<div class="inner no-scroll" (wheel)="blockScroll($event)">
In my app.component.ts I created the event handler to be called:
blockScroll(e) {
console.log(e);
if (e.target !== e.currentTarget) {
return;
}
let eO = e; // e.originalEvent;
var delta = eO.deltaY || -eO.detail;
e.target.scrollTop += delta * 30;
e.stopPropagation();
e.preventDefault();
}
In Firefox Developer Tools I see that the event is properly bound to the <div>:
Now when I use the mouse wheel over the container I see that in nearly all cases the event target is not the bound <div> but rather a <h3> or <p> element inside of the container. I wonder why the wrong element is triggering the scroll event?
This is the expected behavior.
target - element that triggered event (element directly under the mouse pointer at the beginning of the scroll)
currentTarget - element that listens to event (the div element in this case)
So if you were to point at the top of the container and begin scrolling, both target and currentTarget would point to the same div element. But once it's scrolled past the top of the container, the elements directly beneath the mouse pointer would be the <p> or <h3> elements.

Event Listener Scroll or Click

I have a web page with several sections.
To switch from one section to another I don't use scroll but everything is done by clicking (menu, pagination, arrows, etc...)
As soon as the user goes on a section, the background changes color, each section to its color.
I have no problem creating this kind of function but I have a performance question.
Or perhaps it's a question of logic I dunno
It would be better if I bind my event on the scroll and ask for the color change as soon as the section is in the right position
window.addEventListener('scroll', requestAnimationFrame(function(){
if ( sectionPosition === 0 ){
// Do something...
}
}))
or it would be better if I bind my events on the different clickable elements with event delegation
window.addEventListener('click', function(event){
let selector = event.target.getAttribute("href");
if( selector === "#section-one"){
//....
}
if(selector === "#section-two"){
//....
}
})
I think the second option is fine, adding listener on scroll will cause calling the callback with each px you scroll so make the action explicit is better than implicit with many unneeded calls
For the best you need to add click event listener on each element not on the whole window to avoid firing the click callback with any click.
To add click event on targeted item
const sectionOneEl = document.querySelector('#section-one');
sectionOneEl.addEventListener('click', ev => {
// section one click handler
});

Scrolling a 'Horizontally Scrollable div element' makes the parent scroll as well

I have implemented a TabbarController where in the user can swipe through different tabs. I have achieved this by adding 'touchstart', 'touchmove' & 'touchend' events. All the tabs have a horizontally scrollable element which when scrolled leads to invoking of 'touchmove' on parent which leads to parent and child scrolling at same time. Is it possible to restrict the scroll to child / restrict the touch event from being passed on from child to parent?
I have tried using 'overflow:hidden' on parent div and also tries using 'prevendefault()' on touch events.
I finally wrote a solution to cater to my problem. I iterate through the DOM objects to check for the scrollable area of the child elements when the Event callback propagates back to the Parent element where the listeners were added.
The Touch Event is not processed for parent if the current touched child has scrollable content.
var element:HTMLElement = event.target;
var cancel:boolean = false;
while (element && element.parentElement){
if (element.scrollWidth > element.clientWidth){
cancel = true;
break;
}
element = element.parentElement;
}

Making the scrolling keys scroll the proper page element

I have a DIV in my page that is scrollable, while no other elements on the page are. (The page layout is fixed with controls above and below the DIV itself.) I would like the arrow keys and page up/page down to scroll the DIV under all circumstances, but I cannot seem to do so unless the DIV actually has the focus. There are other input fields in other DIVs which often have focus. I have tried capturing the arrow keys and page/up down 'keydown' event at the document level and simulating the same event directly (using answers from this question) to the DIV that needs to scroll, but no scrolling occurs. I know the event is being dispatched because if I attach an event handler I see it, but for some reason it doesn't cause any scrolling. I have also tried setting the "tabIndex" attribute of the DIV with no difference.
How can I designate a specific element to receive specific keys like this? It is extremely user unfriendly to require a specific element to be focused for certain keys to work, when those keys only make sense for a single element on the page. Having to constantly switch focus from another element to the scrollable area to scroll and back to enter data just isn't acceptable.
I have seen suggestions that scrolling can be simulated by other means, but I want to avoid that route because this doesn't always produce identical results, and I also want to generalize it to other kinds of key events and action besides scrolling.
You can scroll any element by adjusting its scrollTop DOM property.
If you capture all the keydown events on the document and then decide on what action you want to take depending on the key pressed (use the which property of the event object) and maybe some other circumstances (inputs focused, controls checked etc.) you can easily scroll your div. Check out this fiddle for a simple demo.
you can you keypress or keyDown events on the document and trigger actions on your DIV.
$(document).ready(function(){
$(document).on("keydown", handleKeyDown);
function handleKeyDown(evt) {
var code = parseInt(evt.keyCode); // the key Code of the key which was pressed during the event /and parses it and returns a 'integer'.
if(code == 38){ // 38 is the keycode for UP key on the keyboard
alert("up");
} else if(code == 40) // 40 is the keycode for down key on the keyboard.
alert("down");
}
}
});
and as explained in breif by Tadeáš Peták you can use the scrollTop DOM property to scroll any element, enjoy.

How can I detect when a certain DIV has changed size without polling? I.e., I want a resize event listener?

So I am running ads on a website that I have and one of the ads periodically changes the dimensions of the DIV that it is in -- it grows and shrinks and shows bouncing things and flashing lights and sparkles, etc. This is fantastic and I love it.
One problem, however, is that the layout of other elements on my page is screwed up when this happens.
This is no big deal though -- all I have to do is add an event listener to the DIV element in question and listen for resizing events. When they occur, I will run a callback function that will adjust the layout of the other elements of my site.
My problem is that the resize event listener is only available for the window object itself, not for other elements in the DOM. How can I listen for resizing events on a particular DIV without polling?
I would like to do something like:
$('my-div-id').on('resize', function() {
do_things();
adjust_layout();
etc();
});
You could use a window.setInterval, that checks every x ms if the element in question has changed size:
var ElementSize = $("#element").width();
window.setInterval(function(){
if( $("#element").width() != ElementSize )
{
ElementSize = $("#element").width();
redolayout();
}
}, 50);
function redolayout()
{
// Add code here to resize other elements according to the change.
}
Another option: https://github.com/sdecima/javascript-detect-element-resize

Categories