Stop propagation at capture phase & continue on bubble phase - javascript

I'm wondering if there's a clean way to control event propagation where I can stop an event from going further down, but bubble back up from there:
<div className="App">
<div
style={{
background: "black",
width: "100%",
height: 400
}}
onMouseUp={(e) => {
alert("outer div");
}}
>
<div
style={{
background: "red",
width: "90%",
height: 300
}}
onMouseUp={(e) => {
alert("middle div");
}}
onMouseUpCapture={(e) => {
//want to skip inner div but
//have middle & outer div alerted
}}
>
<div
style={{
background: "blue",
width: "80%",
height: 150
}}
onMouseUp={(e) => {
alert("inner div");
}}
></div>
</div>
</div>
</div>
Here I want to skip all onClick/onMouseUp events from the middle div but still retain the events that bubble up from the middle div. Is there a way to cleanly achieve this? For context, I am implementing a draggable button that has a react-dom link to it and I can't seem to prevent it from navigating when I let go after dragging.

Use Event.stopPropgation().
stopPropagation('#middle-div', 'mouseup');
function stopPropagation(id, event) {
$(id).on(event, function(e) {
alert("middle div");
e.stopPropagation();
return false;
});
}

Related

Is there a way to still show onMouseEnter when trying to navigate to a Sub Menu

I have an application with menu and submenu. The submenu is supposed to display on mouse enter and it should remain on the screen so that i can navigate to the submenu. I am using onMouseEnter and onMouseLeave
import React, {useState} from "react";
export default function ShowButtonHover() {
const [style, setStyle] = useState({display: 'none'});
return (
<div className="App">
<div style={{border: '1px solid gray', width: 300, height: 300, padding: 10, margin: 100}}
onMouseEnter={e => {
setStyle({display: 'block'});
}}
onMouseLeave={e => {
setStyle({display: 'none'})
}}
>
<p>Show Sub Menu</p>
</div>
<div style={style}>
<div><a href='/sub-1'>Sub Menu 1</a></div>
<div><a href='/sub-2'>Sub Menu 2</a></div>
</div>
</div>
);
}
Is there a way to make the display still remain so i can choose a sub menu and when I leave the main div, It disappears.

Separate onClick event for parent and child element

I have JSX code like this:
<div id="parent" onClick={clickOnParent} style={{ width: 100, height: 100 }}>
<div id="child" onClick={clickOnChild} style={{ width: 20, height: 20 }} />
</div>
When I click on parent (outside the child) it will run clickOnParent, and when I click the child it will run both clickOnParent and clickOnChild of course.Now I want to trigger only clickOnChild and ignore clickOnParent when clicking exactly on the child. How can I do?
Use Event.stopPropagation()
const clickOnChild = (event) => {
event.stopPropagation();
...
}

Fire react "onMouseMove" event when css "pointer-events-none" is set

I have a React Component with an absolute positioned div which overlays other content in my application. The div is used to fire react's onMouseMove event.
I want to set the css value pointer-events-none so all components underneath the div are still clickable, have pointer events etc. Whatever when pointer-events-none is present, the onMouseMove event will not fire anymore. Everything should behave like the overlay div is not present, it should just fire onMouseMove.
The code structure looks like this:
<button>I should be clickable</button>
<div>
<div
style={{
opacity: 0,
position: `absolute`,
top: `50px`,
left: `50px`,
width: `30vw`,
height: `30vh`,
pointerEvents: `none`,
}}
onMouseMove={() => {
console.log(`Fire!`)
}}
>
Overlay
</div>
<button>I should be clickable</button>
<a>I should be clickabel</a>
</div>
<button>I should be clickable</button>
I think I'm missing something or have chosen a completely wrong path here.
Thanks a lot for your help!
You need to place overlay div at the root (in such case events will propagate), remove pointerEvents rule and opacity so that the content inside div would be visible:
<div
style={{
position: `absolute`,
top: `50px`,
left: `50px`,
width: `30vw`,
height: `30vh`
}}
onMouseMove={() => {
console.log(`Fire!`)
}}
>
<button>I should be clickable</button>
<button>I should be clickable</button>
<a>I should be clickable</a>
<button>I should be clickable</button>
</div>

use ref in reactjs-popup trigger

I have a react-table component with custom column header
const popupRef = createRef();
const column = [{
Header: () =>
<div ref={popupRef} className="eye-icon">
<img src={icon}/>
</div>
fixed: "left",
sortable: false,
headerClassName: "table-header-class",
className: "table-row-class",
width: 70
}];
And I have a reactjs-popup that I want to be triggered after I press on that component.
return (
<div>
<Popup
className="popup"
closeOnDocumentClick
trigger={popupRef.current}
arrow={true}
repositionOnResize={true}
on="click"
position="bottom left"
>
<div className="popup">
<span>popup</span>
</div>
</Popup>
<div className="table">
<ReactTableFixedColumns
showPagination={false}
defaultPageSize={selectedTestsLength}
data={data}
style={{height: "73vh"}}
columns={column}
/>
</div>
</div>
);
It doesn't work.
Of course I can make onClick event in header's div to forcly open the popup with reactjs-popup open property - but it appears on the center of the screen and it looks like modal, so this approach is not suitable, I want it to stick to the div, to be placed in correct place.
I think you are using the wrong approach here. Refs are not needed to achieve what you want.
Just simply declare the Popup inline inside the header:
const column = [{
Header: () =>
<Popup trigger={
<div ref={popupRef} className="eye-icon">
<img src={icon}/>
</div>
}>
<div className="popup">
<span>popup</span>
</div>
</Popup>
fixed: "left",
sortable: false,
headerClassName: "table-header-class",
className: "table-row-class",
width: 70
}];
I don't have access to your full code so I can't tell for sure but that should give you the idea.
I just did an empty div and put trigger in it
trigger={<div className="sample-trigger"></div>}
.sample-trigger {
width: 1px;
height: 1px;
display: block;
visibility: hidden;
}
In the main div I am using to trigger the popup I set the onClick to change the state of {wasPopupOpen}
<Popup
className="popup"
closeOnDocumentClick
open={wasEyePopupOpen}...
I also make some adjustmenst on popup window so it looks like inside of that div.

Adding click event to React.Js

I'm learning React.Js. I'm trying to attach an event to write something in the console, however i cant get my function to trigger. Does anyone know how i would attach an onClick event to a react div? I apologise if this is a basic question but ive tried several different methods and none of them are working.
I have tried the two ways of triggering the function shown below but neither is working.
So, Ive realised that the reason that the events were not working was because I was rendering server side. If i render on the client then the event triggers. Does anyone know how to make it trigger if i have initially rendered on the server?
class Individual extends React.Component {
handleClick = () => {
alert("GREAT");
}
render() {
const indDiv = {
margin: '5px',
width: '100px',
height: '120px',
cursor: 'pointer',
border: '5px solid pink',
color: 'blue',
float: 'left'
};
return (
<div>
<div onClick={this.handleClick.bind(this)}>
Alert 1
</div>
<div onClick={() => this.handleClick}>
Alert 2
</div>
<div style={indDiv}>
{this.props.num}. {this.props.name}.
</div>
</div>
);
}
}
Thank you to everyone that contributed to this. After everything i found that because i had initially created this as a server rendered piece, I had to attach the events after the page had rendered. I was using ReactJS.Net and had to initialize it seperately using hydrate.
Both the ways of calling handler function is incorrect in your code.
In your code handleClick is an arrow function hence manual binding is not required.
If it is not an arrow function then the manual binding should be done always in constructor only. Never do binding anywhere else like you did in render.
When you use onClick={() => this.handleClick} this is wrong. It should be onClick={()=> this.handleClick()}. If no Paranthesis then this is correct onClick={this.handleClick}
So change
<div onClick={this.handleClick.bind(this)}>
Alert 1
</div>
<div onClick={() => this.handleClick}>
Alert 2
</div>
To
<div onClick={()=> this.handleClick()}>
Alert 1
</div>
<div onClick={() => this.handleClick()}>
Alert 2
</div>
The reason you should not do binding anywhere else in the component except constructor because for eg you did binding directly in render so what happens in this case is it creates a new function in webpack bundle file every time the component renders and re renders again hence bundle file grows large. Hence it is recommended to bind it only in constructor
You need to declare the handler method after the render method. Here is a basic implementing of your code in jsfiddle.
https://jsfiddle.net/ufyxwv8p/
class Individual extends React.Component {
render() {
const indDiv = {
margin: '5px',
width: '100px',
height: '120px',
cursor: 'pointer',
border: '5px solid pink',
color: 'blue',
float: 'left'
};
return (
<div>
<div onClick={this.handleClick}>
Click to show in console
</div>
<div style={indDiv}>
{this.props.num}. {this.props.name}.
</div>
</div>
);
}
handleClick = () => {
console.log('this is:', this);
}
}
ReactDOM.render(<Individual/>,document.getElementById("app"))
here try like this the way you are defining your handleclick function is wrong i have edited your code online on sandbox to make it work. call function the way you are calling on Alert 1 than define function the way I have uploaded an image
Link of codesandbox of your code check that
Check this image of that code if you dont have time to go through whole code
The click handler on Alert 1 is already working. It's not necessary to bind when you use a the () => {} class properties syntax.
Your click handler on Alert 2 isn't working because you've written an inline arrow function which returns another function. You need to call it, like () => this.handleClick().
Here is a working snippet of your code.
class Individual extends React.Component {
handleClick = () => {
alert("GREAT");
};
render() {
const indDiv = {
margin: "5px",
width: "100px",
height: "120px",
cursor: "pointer",
border: "5px solid pink",
color: "blue",
float: "left"
};
return (
<div>
<div onClick={this.handleClick}>Alert 1</div>
<div onClick={() => this.handleClick()}>Alert 2</div>
<div style={indDiv}>
{this.props.num}. {this.props.name}.
</div>
</div>
);
}
}
ReactDOM.render(<Individual />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
You have to use bind
onClick={this.handleClick.bind(this)}
or use arrow function
onClick={()=>this.handleClick()}
class Individual extends React.Component {
handleClick = () => {
alert("GREAT");
};
render() {
const indDiv = {
margin: "5px",
width: "100px",
height: "120px",
cursor: "pointer",
border: "5px solid pink",
color: "blue",
float: "left"
};
return (
<div>
<div onClick={this.handleClick}>Alert 1</div>
<div onClick={this.handleClick}>Alert 2</div>
<div style={indDiv}>
{this.props.num}. {this.props.name}.
</div>
</div>
);
}
}
ReactDOM.render(<Individual />, document.getElementById("app"));

Categories