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();
...
}
Related
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;
});
}
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>
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.
My question in the title probably looks vague. And I sketched an example for the question:
container.onclick = () => {
alert(0);
};
content.onclick = () => {
alert("how can I prevent here appearance alert(0) from parent element event?");
//how can I prevent parent event by content clicked?
};
#container{
height: 100px;
background-color: gray;
}
#content{
height: 50px;
width: 150px;
background-color: green;
}
<div id="container">
<div id="content"></div>
</div>k
This is a simple example. In a real project, I can't combine these two events into one, because the first one is programmatically assigned somewhere in the bowels of my framework and it shouldn't be removed from the EventListener after clicking on content
In General, is it possible to somehow interrupt the execution of the call chain event by clicking in the DOM layers? I tried to do this:
content.onclick = () => {
alert("how can I prevent here appearance alert(0) from parent element event?");
e.preventDefault();
return false;
//how can I prevent parent event by content clicked?
};
But this, of course, was not successful
You should pass the event by dependency injection to the specific method (content.onclick) and then stop the propagation of it.
container.onclick = () => {
alert(0);
};
content.onclick = (e) => {
e.stopPropagation();
alert("VoilĂ , this prevent that appears alert(0) from parent element event.");
};
#container{
height: 100px;
background-color: gray;
}
#content{
height: 50px;
width: 150px;
background-color: green;
}
<div id="container">
<div id="content"></div>
</div>
For this, you can use stop propogation of js like this
<div id="container">
<div id="content" onclick="event.stopPropagation();">
</div>
</div>
So when you click on content it will not trigger container event only.
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"));