score:60
in the element i have added mousedown
and mouseup
like this:
onmousedown={this.props.onmousedown} onmouseup={this.props.onmouseup}
then in the parent i do this:
componentdidmount: function () {
window.addeventlistener('mousedown', this.pageclick, false);
},
pageclick: function (e) {
if (this.mouseisdownoncalendar) {
return;
}
this.setstate({
showcal: false
});
},
mousedownhandler: function () {
this.mouseisdownoncalendar = true;
},
mouseuphandler: function () {
this.mouseisdownoncalendar = false;
}
the showcal
is a boolean that when true
shows in my case a calendar and false
hides it.
score:-1
use the excellent react-onclickoutside mixin:
npm install --save react-onclickoutside
and then
var component = react.createclass({
mixins: [
require('react-onclickoutside')
],
handleclickoutside: function(evt) {
// ...handling code goes here...
}
});
score:0
i found a simpler way about this.
you just need to add onhide(this.closefunction)
on the modal
<modal onhide={this.closefunction}>
...
</modal>
assuming you have a function to close the modal.
score:1
super late to the party, but i've had success with setting a blur event on the parent element of the dropdown with the associated code to close the dropdown, and also attaching a mousedown listener to the parent element that checks if the dropdown is open or not, and will stop the event propagation if it is open so that the blur event won't be triggered.
since the mousedown event bubbles up this will prevent any mousedown on children from causing a blur on the parent.
/* some react component */
...
showfoo = () => this.setstate({ showfoo: true });
hidefoo = () => this.setstate({ showfoo: false });
clicked = e => {
if (!this.state.showfoo) {
this.showfoo();
return;
}
e.preventdefault()
e.stoppropagation()
}
render() {
return (
<div
onfocus={this.showfoo}
onblur={this.hidefoo}
onmousedown={this.clicked}
>
{this.state.showfoo ? <foocomponent /> : null}
</div>
)
}
...
e.preventdefault() shouldn't have to be called as far as i can reason but firefox doesn't play nice without it for whatever reason. works on chrome, firefox, and safari.
score:2
you could use ref
s to achieve this, something like the following should work.
add the ref
to your element:
<div ref={(element) => { this.myelement = element; }}></div>
you can then add a function for handling the click outside of the element like so:
handleclickoutside(e) {
if (!this.myelement.contains(e)) {
this.setstate({ myelementvisibility: false });
}
}
then finally, add and remove the event listeners on will mount and will unmount.
componentwillmount() {
document.addeventlistener('click', this.handleclickoutside, false); // assuming that you already did .bind(this) in constructor
}
componentwillunmount() {
document.removeeventlistener('click', this.handleclickoutside, false); // assuming that you already did .bind(this) in constructor
}
score:3
- create a fixed layer that spans the whole screen (
.backdrop
). - have the target element (
.target
) outside the.backdrop
element and with a greater stacking index (z-index
).
then any click on the .backdrop
element will be considered "outside of the .target
element".
.click-overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
}
.target {
position: relative;
z-index: 2;
}
- here is an example: http://jsfiddle.net/lhmwd/
- more on the discussion: https://github.com/facebook/react/issues/579
score:4
i voted up one of the answers even though it didn't work for me. it ended up leading me to this solution. i changed the order of operations slightly. i listen for mousedown on the target and mouseup on the target. if either of those return true, we don't close the modal. as soon as a click is registered, anywhere, those two booleans { mousedownonmodal, mouseuponmodal } are set back to false.
componentdidmount() {
document.addeventlistener('click', this._handlepageclick);
},
componentwillunmount() {
document.removeeventlistener('click', this._handlepageclick);
},
_handlepageclick(e) {
var wasdown = this.mousedownonmodal;
var wasup = this.mouseuponmodal;
this.mousedownonmodal = false;
this.mouseuponmodal = false;
if (!wasdown && !wasup)
this.close();
},
_handlemousedown() {
this.mousedownonmodal = true;
},
_handlemouseup() {
this.mouseuponmodal = true;
},
render() {
return (
<modal onmousedown={this._handlemousedown} >
onmouseup={this._handlemouseup}
{/* other_content_here */}
</modal>
);
}
this has the advantage that all the code rests with the child component, and not the parent. it means that there's no boilerplate code to copy when reusing this component.
score:5
i have written a generic event handler for events that originate outside of the component, react-outside-event.
the implementation itself is simple:
- when component is mounted, an event handler is attached to the
window
object. - when an event occurs, the component checks whether the event originates from within the component. if it does not, then it triggers
onoutsideevent
on the target component. - when component is unmounted, the event handler is detacthed.
import react from 'react';
import reactdom from 'react-dom';
/**
* @param {reactclass} target the component that defines `onoutsideevent` handler.
* @param {string[]} supportedevents a list of valid dom event names. default: ['mousedown'].
* @return {reactclass}
*/
export default (target, supportedevents = ['mousedown']) => {
return class reactoutsideevent extends react.component {
componentdidmount = () => {
if (!this.refs.target.onoutsideevent) {
throw new error('component does not defined "onoutsideevent" method.');
}
supportedevents.foreach((eventname) => {
window.addeventlistener(eventname, this.handleevent, false);
});
};
componentwillunmount = () => {
supportedevents.foreach((eventname) => {
window.removeeventlistener(eventname, this.handleevent, false);
});
};
handleevent = (event) => {
let target,
targetelement,
isinside,
isoutside;
target = this.refs.target;
targetelement = reactdom.finddomnode(target);
isinside = targetelement.contains(event.target) || targetelement === event.target;
isoutside = !isinside;
if (isoutside) {
target.onoutsideevent(event);
}
};
render() {
return <target ref='target' {... this.props} />;
}
}
};
to use the component, you need wrap the target component class declaration using the higher order component and define the events that you want to handle:
import react from 'react';
import reactdom from 'react-dom';
import reactoutsideevent from 'react-outside-event';
class player extends react.component {
onoutsideevent = (event) => {
if (event.type === 'mousedown') {
} else if (event.type === 'mouseup') {
}
}
render () {
return <div>hello, world!</div>;
}
}
export default reactoutsideevent(player, ['mousedown', 'mouseup']);
score:11
for your specific use case, the currently accepted answer is a tad over-engineered. if you want to listen for when a user clicks out of a dropdown list, simply use a <select>
component as the parent element and attach an onblur
handler to it.
the only drawbacks to this approach is that it assumes the user has already maintained focus on the element, and it relies on a form control (which may or may not be what you want if you take into account that the tab
key also focuses and blurs elements) - but these drawbacks are only really a limit for more complicated use cases, in which case a more complicated solution might be necessary.
var dropdown = react.createclass({
handleblur: function(e) {
// do something when user clicks outside of this element
},
render: function() {
return (
<select onblur={this.handleblur}>
...
</select>
);
}
});
score:17
look at the target of the event, if the event was directly on the component, or children of that component, then the click was inside. otherwise it was outside.
react.createclass({
clickdocument: function(e) {
var component = react.finddomnode(this.refs.component);
if (e.target == component || $(component).has(e.target).length) {
// inside of the component.
} else {
// outside of the component.
}
},
componentdidmount: function() {
$(document).bind('click', this.clickdocument);
},
componentwillunmount: function() {
$(document).unbind('click', this.clickdocument);
},
render: function() {
return (
<div ref='component'>
...
</div>
)
}
});
if this is to be used in many components, it is nicer with a mixin:
var clickmixin = {
_clickdocument: function (e) {
var component = react.finddomnode(this.refs.component);
if (e.target == component || $(component).has(e.target).length) {
this.clickinside(e);
} else {
this.clickoutside(e);
}
},
componentdidmount: function () {
$(document).bind('click', this._clickdocument);
},
componentwillunmount: function () {
$(document).unbind('click', this._clickdocument);
},
}
see example here: https://jsfiddle.net/0lshs7mg/1/
score:73
using the life-cycle methods add and remove event listeners to the document.
react.createclass({
handleclick: function (e) {
if (this.getdomnode().contains(e.target)) {
return;
}
},
componentwillmount: function () {
document.addeventlistener('click', this.handleclick, false);
},
componentwillunmount: function () {
document.removeeventlistener('click', this.handleclick, false);
}
});
check out lines 48-54 of this component: https://github.com/i-like-robots/react-tube-tracker/blob/91dc0129a1f6077bef57ea4ad9a860be0c600e9d/app/component/tube-tracker.jsx#l48-54
Source: stackoverflow.com
Related Query
- How to listen for click events that are outside of a component
- How to make ref to component and listen for click outside?
- How do react hooks determine the component that they are for?
- How to submit form from a button outside that component in React?
- How do I write a storybook story for a component that has redux-connected component as grandchild?
- React: How to listen to child component events
- How can I write a unit test for a react component that calls reduxjs's mapStateToProps?
- How to Listen for Events in children components in React Native?
- How do I test component methods on a React component that are defined as arrow functions (class properties)?
- How do I manage state on a React component that can have state changed from the parent or from events upon it?
- How to detect matched route from a component outside of the <Route/> component that was matched using react-router?
- How can we write a click handler for a Stateless Function Component in React JS
- How test callback click in child component that was passed from parent component?
- How do I call a function on button click to listen for another mouse click in React Hooks?
- How to pass react hook state to another component for each click
- Correct approach for updating an already rendered ReactJS component from outside that component
- How to get React to listen for a click event called in Jquery
- How do I write a test for a component that uses React.cloneElement?
- How to add text based on click which is outside the Editor component , to the Editor
- How to disable click events for props.children in React?
- Update state of a functional component from outside of that component(on click of button in another file) in React
- How to pass on data that are fetched from Firestore as props to a component
- How to update a key for all my objects that are in an array
- How can I pass default theme that is provided by MUI5 and create a style for any component in MUI5?
- How to render a component outside the component that contains the function that renders the first component?
- How to spy on history object from outside the component that uses Router?
- How to refresh a nested Component view that shows the result for a search being done in React
- How to redirect to a url along with a component in react such that props passed to the component are not lost
- how do you define the proptypes for the css classes that are passed from parent component?
- When testing a React component that renders fetched API data, how best to wait for that data before making any assertions?
More Query from same tag
- Apply inline style to an element in React from a child element
- Why changes in Checkbox's value are not displayed?
- React router long nested routing
- "Link" from "react-router-dom" inside "extra" in antd card not working
- Cannot read property 'props' of undefined - React Router
- Control order of TAB with javascript (react)
- React-Flow: Can you pass props to a custom node in React-Flow?
- What is the importance of PropTypes in React?
- Draft-js JSON to EditorState does not update
- TypeError: This condition will always return 'false' since the types '"id"' and '"en"' have no overlap
- Custom React-Bootstrap Popover
- How to hide MUI React ListItem?
- React styles object not being applied
- React - 2 input field dependent on each other - infinite loop
- How to call an action from inside an options object?
- Create-React-App with TypeScript failing to compile after importing Semantic UI
- How can I change the class of an element dynamically via url in React?
- How to make svg animation scaling from the center and not upper-left corner?
- How to test componentDidUpdate()?
- JavaScript LocaleDateString back to Date Object
- React how to wait for component/page to render to call function
- Upload files from (Fast)API to Azure Blob Storage
- unique default state/class to react toggle
- Make use of event handler in React Component for TSX tag
- Create tag using Autocomplete material UI when user input anything
- How to show an image in tabulator
- (React fetch data)what is the difference between these two
- Test react component can't get clientWidth
- Is it a bad idea to use CustomEvent in a react global component like a snackbar in the AppRoot?
- Symfony 4 + ReactJS Not Working Without Any Error