Giter Club home page Giter Club logo

react-onclickoutside's Introduction

npm version Build Status npm

⚠️ Open source is free, but developer time isn't ⚠️

This package needs your support to stay maintained. If you work for an organization whose website is better off using react-onclickoutside than rolling its own code solution, please consider talking to your manager to help fund this project. Open Source is free to use, but certainly not free to develop. If you have the means to reward those whose work you rely on, please consider doing so.

An onClickOutside wrapper for React components

This is a React Higher Order Component (HOC) that you can use with your own React components if you want to have them listen for clicks that occur somewhere in the document, outside of the element itself (for instance, if you need to hide a menu when people click anywhere else on your page).

Note that this HOC relies on the .classList property, which is supported by all modern browsers, but not by deprecated and obsolete browsers like IE (noting that Microsoft Edge is not Microsoft Internet Explorer. Edge does not have any problems with the classList property for SVG elements). If your code relies on classList in any way, you want to use a polyfill like dom4.

This HOC supports stateless components as of v5.7.0, and switched to using transpiled es6 classes rather than createClass as of v6.

Sections covered in this README

Installation

Only install this HoC if you're still extending the Component class, something which the React documentation doesn't even cover anymore because they went all-in on functional components with hooks.

If you're using hooks, which React says you should be, don't install this HoC and instead read this section, below.

If you're still stuck with Component classes, then you can install this HoC using npm:

$> npm install react-onclickoutside --save

(or --save-dev depending on your needs). You then use it in your components as:

Usage

Functional Component with UseState Hook

This HoC does not support functional components, as it relies on class properties and component instances. However, you almost certainly don't need this HoC in modern (React 16+) functional component code, as a simple function will do the trick just fine. E.g.:

function listenForOutsideClicks(listening, setListening, menuRef, setIsOpen) {
  return () => {
    if (listening) return;
    if (!menuRef.current) return;
    setListening(true);
    [`click`, `touchstart`].forEach((type) => {
      document.addEventListener(`click`, (evt) => {
        if (menuRef.current.contains(evt.target)) return;
        setIsOpen(false);
      });
    });
  }
}

Used in a functional component as:

import React, { useEffect, useState, useRef } from "react";
import listenForOutsideClicks from "./somewhere";

const Menu = () => {
  const menuRef = useRef(null);
  const [listening, setListening] = useState(false);
  const [isOpen, setIsOpen] = useState(false);  
  const toggle = () => setIsOpen(!isOpen);

  useEffect(listenForOutsideClick(
    listening,
    setListening,
    menuRef,
    setIsOpen,
  ));

  return (
    <div ref={menuRef} className={isOpen ? "open" : "hidden"}>
      <h1 onClick={toggle}>...</h1>
      <ul>...</ul>
    </div>
  );
};

export default Menu;

Example: https://codesandbox.io/s/trusting-dubinsky-k3mve

ES6 Class Component

import React, { Component } from "react";
import onClickOutside from "react-onclickoutside";

class MyComponent extends Component {
  handleClickOutside = evt => {
    // ..handling code goes here...
  };
}

export default onClickOutside(MyComponent);

CommonJS Require

// .default is needed because library is bundled as ES6 module
var onClickOutside = require("react-onclickoutside").default;
var createReactClass = require("create-react-class");

// create a new component, wrapped by this onclickoutside HOC:
var MyComponent = onClickOutside(
  createReactClass({
    // ...,
    handleClickOutside: function(evt) {
      // ...handling code goes here...
    }
    // ...
  })
);

Ensuring there is a click handler

Note that if you try to wrap a React component class without a handleClickOutside(evt) handler like this, the HOC will throw an error. In order to use a custom event handler, you can specify the function to be used by the HOC as second parameter (this can be useful in environments like TypeScript, where the fact that the wrapped component does not implement the handler can be flagged at compile-time):

// load the HOC:
import React, { Component } from "react";
import onClickOutside from "react-onclickoutside";

// create a new component, wrapped below by onClickOutside HOC:
class MyComponent extends Component {
  // ...
  myClickOutsideHandler(evt) {
    // ...handling code goes here...
  }
  // ...
}
var clickOutsideConfig = {
  handleClickOutside: function(instance) {
    return instance.myClickOutsideHandler;
  }
};
var EnhancedComponent = onClickOutside(MyComponent, clickOutsideConfig);

Note that if you try to wrap a React component with a custom handler that the component does not implement, the HOC will throw an error at run-time.

Regulate which events to listen for

By default, "outside clicks" are based on both mousedown and touchstart events; if that is what you need, then you do not need to specify anything special. However, if you need different events, you can specify these using the eventTypes property. If you just need one event, you can pass in the event name as plain string:

<MyComponent eventTypes="click" ... />

For multiple events, you can pass in the array of event names you need to listen for:

<MyComponent eventTypes={["click", "touchend"]} ... />

Regulate whether or not to listen for outside clicks

Wrapped components have two functions that can be used to explicitly listen for, or do nothing with, outside clicks

  • enableOnClickOutside() - Enables outside click listening by setting up the event listening bindings.
  • disableOnClickOutside() - Disables outside click listening by explicitly removing the event listening bindings.

In addition, you can create a component that uses this HOC such that it has the code set up and ready to go, but not listening for outside click events until you explicitly issue its enableOnClickOutside(), by passing in a properly called disableOnClickOutside:

import React, { Component } from "react";
import onClickOutside from "react-onclickoutside";

class MyComponent extends Component {
  // ...
  handleClickOutside(evt) {
    // ...
  }
  // ...
}
var EnhancedComponent = onClickOutside(MyComponent);

class Container extends Component {
  render(evt) {
    return <EnhancedComponent disableOnClickOutside={true} />;
  }
}

Using disableOnClickOutside() or enableOnClickOutside() within componentDidMount or componentWillMount is considered an anti-pattern, and does not have consistent behaviour when using the mixin and HOC/ES7 Decorator. Favour setting the disableOnClickOutside property on the component.

Regulate whether or not to listen to scrollbar clicks

By default this HOC will listen for "clicks inside the document", which may include clicks that occur on the scrollbar. Quite often clicking on the scrollbar should close whatever is open but in case your project invalidates that assumption you can use the excludeScrollbar property to explicitly tell the HOC that clicks on the scrollbar should be ignored:

import React, { Component } from "react";
import onClickOutside from "react-onclickoutside";

class MyComponent extends Component {
  // ...
}
var EnhancedComponent = onClickOutside(MyComponent);

class Container extends Component {
  render(evt) {
    return <EnhancedComponent excludeScrollbar={true} />;
  }
}

Alternatively, you can specify this behavior as default for all instances of your component passing a configuration object as second parameter:

import React, { Component } from "react";
import onClickOutside from "react-onclickoutside";

class MyComponent extends Component {
  // ...
}
var clickOutsideConfig = {
  excludeScrollbar: true
};
var EnhancedComponent = onClickOutside(MyComponent, clickOutsideConfig);

Regulating evt.preventDefault() and evt.stopPropagation()

Technically this HOC lets you pass in preventDefault={true/false} and stopPropagation={true/false} to regulate what happens to the event when it hits your handleClickOutside(evt) function, but beware: stopPropagation may not do what you expect it to do.

Each component adds new event listeners to the document, which may or may not cause as many event triggers as there are event listening bindings. In the test file found in ./test/browser/index.html, the coded uses stopPropagation={true} but sibling events still make it to "parents".

Marking elements as "skip over this one" during the event loop

If you want the HOC to ignore certain elements, you can tell the HOC which CSS class name it should use for this purposes. If you want explicit control over the class name, use outsideClickIgnoreClass={some string} as component property, or if you don't, the default string used is ignore-react-onclickoutside.

Older React code: "What happened to the Mixin??"

Due to ES2015/ES6 class syntax making mixins essentially impossible, and the fact that HOC wrapping works perfectly fine in ES5 and older versions of React, as of this package's version 5.0.0 no Mixin is offered anymore.

If you absolutely need a mixin... you really don't.

But how can I access my component? It has an API that I rely on!

No, I get that. I constantly have that problem myself, so while there is no universal agreement on how to do that, this HOC offers a getInstance() function that you can call for a reference to the component you wrapped, so that you can call its API without headaches:

import React, { Component } from 'react'
import onClickOutside from 'react-onclickoutside'

class MyComponent extends Component {
  // ...
  handleClickOutside(evt) {
    // ...
  }
  ...
}
var EnhancedComponent = onClickOutside(MyComponent);

class Container extends Component {
  constructor(props) {
    super(props);
    this.getMyComponentRef = this.getMyComponentRef.bind(this);
  }

  someFunction() {
    var ref = this.myComponentRef;
    // 1) Get the wrapped component instance:
    var superTrueMyComponent = ref.getInstance();
    // and call instance functions defined for it:
    superTrueMyComponent.customFunction();
  }

  getMyComponentRef(ref) {
    this.myComponentRef = ref;
  }

  render(evt) {
    return <EnhancedComponent disableOnClickOutside={true} ref={this.getMyComponentRef}/>
  }
}

Note that there is also a getClass() function, to get the original Class that was passed into the HOC wrapper, but if you find yourself needing this you're probably doing something wrong: you really want to define your classes as real, require'able etc. units, and then write wrapped components separately, so that you can always access the original class's statics etc. properties without needing to extract them out of a HOC.

Which version do I need for which version of React?

If you use React 0.12 or 0.13, version 2.4 and below will work.

If you use React 0.14, use v2.5 through v4.9, as these specifically use react-DOM for the necessary DOM event bindings.

If you use React 15, you can use v4.x, which offers both a mixin and HOC, or use v5.x, which is HOC-only.

If you use React 15.5, you can use v5.11.x, which relies on createClass as supplied by create-react-class rather than React.createClass.

If you use React 16 or 15.5 in preparation of 16, use v6.x, which uses pure class notation.

Support-wise, only the latest version will receive updates and bug fixes.

I do not believe in perpetual support for outdated libraries, so if you find one of the older versions is not playing nice with an even older React: you know what to do, and it's not "keep using that old version of React".

IE does not support classList for SVG elements!

This is true, but also an edge-case problem that only exists for IE11 (as all versions prior to 11 no longer exist), and should be addressed by you, rather than by thousands of individual libraries that assume browsers have proper HTML API implementations (IE Edge has proper classList support even for SVG).

If you need this to work, you can add a shim for classList to your page(s), loaded before you load your React code, and you'll have instantly fixed every library that you might remotely rely on that makes use of the classList property. You can find several shims quite easily, a good one to start with is the dom4 shim, which adds all manner of good DOM4 properties to "not quite at DOM4 yet" browser implementations.

Eventually this problem will stop being one, but in the mean time you are responsible for making your site work by shimming everything that needs shimming for IE. As such, if you file a PR to fix classList-and-SVG issues specifically for this library, your PR will be closed and I will politely point you to this README.md section. I will not accept PRs to fix this issue. You already have the power to fix it, and I expect you to take responsibility as a fellow developer to shim what you need instead of getting obsolete quirks supported by libraries whose job isn't to support obsolete quirks.

To work around the issue you can use this simple shim:

if (!("classList" in SVGElement.prototype)) {
  Object.defineProperty(SVGElement.prototype, "classList", {
    get() {
      return {
        contains: className => {
          return this.className.baseVal.split(" ").indexOf(className) !== -1;
        }
      };
    }
  });
}

I can't find what I need in the README

If you've read the whole thing and you still can't find what you were looking for, then the README is missing important information that should be added in. Please file an issue with a request for additional documentation, describing what you were hoping to find in enough detail that it can be used to write up the information you needed.

react-onclickoutside's People

Contributors

agudulin avatar andarist avatar arunthampi avatar bvincent1 avatar calvein avatar chentsulin avatar conoremclaughlin avatar craigdallimore avatar emmahsax avatar h3rmanj avatar jbblanchet avatar jcursoli avatar jochenberger avatar jshthornton avatar jtulk avatar kt3k avatar lorenzos avatar marnusw avatar martijnrusschen avatar ormeirchak avatar phwebi avatar pomax avatar rmdort avatar rudzainy avatar samsch avatar sparksm avatar stevewillard avatar sverrejoh avatar terrierscript avatar vinnymac avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-onclickoutside's Issues

5.1.0 nextProps enabling and disabling conditions identical

Hi,

Love the idea and the work you've put into this library . We're rewriting our site in React and were using it to create some lightweight dropdowns. 5.1.0 seems much faster from 4.x but that's likely due to our limited knowledge of react. Integrating it though we noticed the componentWillReceiveProps if conditions are identical so disableOnClickOutside wasn't being called properly.

See: https://github.com/Pomax/react-onclickoutside/blob/master/index.js#L131

We flipped it and now it's working magnificently. Don't have time to open a proper pull request until next week cause of our tight deadline, but hope this helps and thanks for helping the community through a mostly thankless job. If I've got this wrong, please don't hesitate to let us know. Our fix:

        componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
          if (this.props.disableOnClickOutside && !nextProps.disableOnClickOutside) {
            this.enableOnClickOutside();
          } else if (!this.props.disableOnClickOutside && nextProps.disableOnClickOutside) {
            this.disableOnClickOutside();
          }
        },

Does not work if on initial render component returns null

Didn't have much time to dig this, but if component wrapped with onClickOutside returns null on initial render, and later renders some content, click to new content will be considered outside.

I understand why this happens, but at least let's add a warning when someones renders empty element inside wrapped component.

Bundling seems to be broken with babel 6 due to a typo in module.exports

This (in index.js):

// Node. Note that this does not work with strict
// CommonJS, but only CommonJS-like environments
// that support module.exports
module.exports = factory(require(root, 'react-dom'));

Should probably be this:

// Node. Note that this does not work with strict
// CommonJS, but only CommonJS-like environments
// that support module.exports
module.exports = factory(root, require('react-dom'));

Bring the mixin back.

Obviously, not everyone is using es6 class syntax with React, and I think as the README points out the discussion about how HOCs should work is not completely formalized. I just feel like the mixin was a better approach than wrapping another component in react-onclickoutside.

Throws an error when clicking on an SVGElement in Safari

The click handler throws an error when clicking on an SVGElement in Safari because it cannot call classList.contains on undefined.
This error is caused because SVGElements do not have a classList property in Safari.

Proposed solution:

Check if source.classList is defined before executing source.classList.contains(IGNORE_CLASS)

Support for stateless components

I tried to use this lib with recompose:

const controller = compose(
    withHandlers({
        handleClickOutside: (props) => (event) => null // do something
    }),
    onClickOutside
);

const component = controller((props) => <div>...</div>);

Unfortunately, onClickOutside HOC expects component with handleClickOutside method defined in component itself, so it doesn't work with stateless components.

Right now I'm using simple component using existing API which I use a root component in my stateless one:

@onClickOutside
class OutsideClickHandler extends Component {
  handleClickOutside() {
    this.props.handleClickOutside();
  }

  render() {
    return this.props.children;
  }
}

Question is: Is it worth to include such a component in this library? Is there a better way how to support stateless components or take handler function from props?

Need tests and CI

The error in the most recent release could probably have been avoided

React 15 and Object.assign

React 15 doesnt ship with Object.assign . Getting module not found error

Module not found: Error: Cannot resolve module 'react/lib/Object.assign' in ..../node_modules/react-onclickoutside
 @ ./~/react-onclickoutside/decorator.js 2:19-53

Pass which document events to bind to

As created here: https://github.com/Pomax/react-onclickoutside/blob/master/index.js#L111 .

In my example I have a dialog box that is opened via an onClick of a button. Then I use react-onclickoutside to close the dialog. However, if the user clicks on the button to close the dialog the document 'mousedown' event fires, the dialog wrapper state is set to closed, then the onClick event on the button fires and the dialog is set back to open. Essentially making the dialog flash closed then back open. I can make it work by having the button respond to an onMouseDown which will properly respect the stopPropagation().

It would be helpful to be able to pass in which document listeners to bind to.

I'm using HOC btw, so it's similar to the same design issue as #61.

Thanks!

Internet explorer 11 specific undefined/null reference

I am using leaflet in conjunction with react-onclickoutside, and currently the following code breaks in internet explorer 11(and only internet explorer among the popular browsers). /index.js

  var isSourceFound = function(source, localNode) {
    if (source === localNode) {
      return true;
    }
    // SVG <use/> elements do not technically reside in the rendered DOM, so
    // they do not have classList directly, but they offer a link to their
    // corresponding element, which can have classList. This extra check is for
    // that case.
    // See: http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGUseElement
    // Discussion: https://github.com/Pomax/react-onclickoutside/pull/17
    if (source.correspondingElement) {
      return source.correspondingElement.classList.contains(IGNORE_CLASS);
    }

    return source.classList.contains(IGNORE_CLASS); //This line throws source.classList is undefined error
  };

I realize you guys have updated since I installed the module, but the error would still remain. There should be a check that ensures source.classList is defined before looking for the property contains.
A simple fix is to replace the last line with
return source.classList && source.classList.contains(IGNORE_CLASS);

Cheers!

Broken with React 0.13

The latest version (v4) of react-onclickoutside does not work with React 0.13 since it references React-DOM. Is this intentional? Can you make v4 compatible with React 0.13?

DOMNode may not exist

If a component using this mixin returns null in the initial render, this.getDOMNode() will return null in componentDidMount. If the component later renders something more substantial, clicks that are inside of its new DOM node won't be registered as 'inside'.

React/ES6 handleClickOutside not bound

Before v5.0.0, when you used the HOC, handleClickOutside was bound. Now it seems I have to bind it in my constructor, otherwise I cannot access this.props in my event handler.

constructor() {
  super();
  this.handleClickOutside = this.handleClickOutside.bind(this);
}

Should this be the case?

disableOnClickOutside ES6/2015 class support

When using ES6 classes setting the property <Component disableOnClickOutside={true} />

Will overwrite the ability to use this.props.disableOnClickOutside(); within the component class. A simple solution I'm using now is to rename the property.

if (!this.props.disableOnClickOutside) { this.enableOnClickOutside(); }

to

if (!this.props.disabled) { this.enableOnClickOutside(); }

global is not defined.

I'm installing this mixin through the browser method where root is the window. But in the function itself I receive an error on the console that states global is not defined..

I added global = this; in the function and it fixes it. Is this the right approach?

React 15.0.1 - warning about binding

Hi,
I've recently updated React in my app to version 15.0.1 and since then, this warning has been poping up in console:

app.js:5245 Warning: bind(): You are binding a component method to the component. React does this for you automatically in a high-performance way, so you can safely remove this call. See Dropdown

When I remove react-onclickoutside implementation in my Dropdown component, the warning disappears, obviously. Are you planning to address this issue?

Thanks

[require] AssertionError: path must be a string

4.4.0 breaks compatibility with Babel 5.
Regression introduced in #53.

Error looks like this.

can't execute file: /Users/Greyson/XXX/bin/server.js
    error given was: AssertionError: path must be a string
    at Module.require (module.js:365:3)
    at require (module.js:385:17)
    at registeredComponents (/Users/Greyson/XXX/node_modules/react-datepicker/node_modules/react-onclickoutside/index.js:26:30)
    at Object.<anonymous> (/Users/Greyson/XXX/node_modules/react-datepicker/node_modules/react-onclickoutside/index.js:31:2)
    at Module._compile (module.js:435:26)
    at Module._extensions..js (module.js:442:10)
    at require.extensions.(anonymous function) (/Users/Greyson/XXX/node_modules/babel-core/lib/api/register/node.js:214:7)
    at /Users/Greyson/XXX/node_modules/webpack-isomorphic-tools/babel-transpiled-modules/tools/require hacker.js:219:64
    at webpack_isomorphic_tools.require (/Users/Greyson/XXX/node_modules/webpack-isomorphic-tools/babel-transpiled-modules/index.js:340:11)
    at /Users/Greyson/XXX/node_modules/webpack-isomorphic-tools/babel-transpiled-modules/index.js:297:18
    at Object._module3.default._extensions.(anonymous function) [as .js] (/Users/Greyson/XXX/node_modules/webpack-isomorphic-tools/babel-transpiled-modules/tools/require hacker.js:206:17)
    at Module.load (module.js:356:32)
    at Module._load (module.js:311:12)
    at Function.module._load (/Users/Greyson/XXX/node_modules/piping/lib/launcher.js:32:16)
    at Module.require (module.js:366:17)
    at require (module.js:385:17)

export IGNORE_CLASS from the module

instead of remembering the special className: 'ignore-react-onclickoutside' for ignoring click outside. It would be a better source truth if it was exported from the module and/or have an option to config your own className

4.1.1 dist cannot be used as asset

We aren't able to use 4.1.1 because we have index.js being included directly in an application as an asset. It fails with a syntax error because global is not defined. I'd issue a PR but I'm not entirely sure when or why global would be defined.

Issue was introduced here: #48

Using React 0.14.x

Workaround: downgrade to 4.1.0

handleClickOutside called because child element no longer in DOM

I have an issue where elements inside the OnClickOutside component are removed before the isSourceFound function is called.

Specifically, I'm using https://github.com/JedWatson/react-select (a dropdown component).

<MyOnClickOutsideContainer>
  <ReactSelect />
</MyOnClickOutsideContainer>

Once a value is selected in the <ReactSelect/> component, then handleClickOutside is invoked. This is because isSourceFound looks to see if event.target is contained within MyOnClickOutsideContainer, however event.target isn't contained because it's already been removed from the DOM.

For the time being, I've done:

  componentWillMount(){
    // this was happening because the react-select component was removing its contents before this event would fire.
    // by the time the event fired, the element was already removed from the DOM.
    this._oldHandleClickOutside = this.handleClickOutside;
    this.handleClickOutside     = (evt)=> {
      //http://stackoverflow.com/a/16820058/173957
      if (document.body.contains(evt.target)) {
        return this._oldHandleClickOutside(evt);
      }
    };
  },

Uncaught TypeError - getBoundingClientRect

I keep getting the following error on scrolling my React page:

Uncaught TypeError: Cannot read property 'getBoundingClientRect' of null

in the Helpers file line 116

any thoughts?

Not worked properly when have multiple component using this mixin

I've leaved a comment under this issue:
#35

I don't think it's a reasonable change, the stopImmediatePropagation will block all remaining listeners !
Just think we got two components(like datepicker) with react-onclickoutside on our page , the second one will never work properly because of the stopImmediatePropagation call in the first one's listener.
And this is the problem I meet now: only the first datepicker can close the popup panel properly.
If you really want stopImmediatePropagation in some situations, maybe call it in the handleClickOutside is a better choice.

And I write a demo to show this issue, please note the second component never worked:
http://codepen.io/anon/pen/dYzPmM

and this is the same demo with [email protected] :
http://codepen.io/anon/pen/jbLExp

License

I see by the packages.json that the license is MIT.

Could you include the license file in the new releases ?

Question: stop propagation when clicking outside?

Is there any way to to stop the event from bubbling when clicking outside? I tried something like

handleClickOutside: function(event) {
    event.stopPropagation()
}

I also tried the nativeEvent and other variations of this. It still seems to be triggering other onClick events, for example.

Ignore clicks inside certain elements

I have a requirement where I need the mixin to callback if its click outside a component but with a few exceptions. The method I used was to add the class ignore-react-onclickoutside to whichever elements that I want the mixin to ignore and change this line

found = (source === localNode);

to

found = (source === localNode || source.className.match(/ignore-react-onclickoutside/));

If you think this is a valid feature request (and solution), I can send a pull request (with the appropriate documentation changes as well).

Uncaught ReferenceError: React is not defined @ index.js line 59

This was working in version 0.2.4 but using version 0.2.5 from npm, I get the following error from index.js at line 59...

Uncaught ReferenceError: React is not defined

It looks like you have made changes recently to how the dependencies are loaded. Do I need to do something in order to have React visible to onclickoutside?

onClickOutside is not a function

Whatever I try I get this error onClickOutside is not a function.

I even copied the example code. Only modification I did was to add render() to MyComponent and export default Container to be able to import the component in other places.

What am I doing wrong??

var React = require('react');
var onClickOutside = require('react-onclickoutside');

var MyComponent = onClickOutside(React.createClass({
  handleClickOutside: function(evt) {
    // ...
  },
  render() {
    return this.props.children;
  }
}));

var Container = React.createClass({
  render: function(evt) {
    return <MyComponent disableOnClickOutside={true} />
  }
});

export default Container;

EDIT:
My setup is

  • react 0.14.7
  • react-onclickoutside 4.9.0

Document that calling disableOnClickOutside() in componentDidMount will not work

As per the title, calling this.props.disableOnClickOutside() from componentDidMount() doesn't disable listening. This is using ES2015 class syntax (but not ES7/decorator).

Here is the relevent code snippet:

componentDidMount() {
    this.props.disableOnClickOutside();
}

With this code in my component, handleClickOutside is still being called.

Here is a test case file.
It needs to be compiled with Babel+Webpack. If you want my exact config, you could drop the gist code into my basic-react repo as src/main.js (the html grabs main.js, not main.jsx, but I used .jsx so that gist would highlight correctly). You would just need to do npm install react-onclickoutside --save, and npm run dev, then serve public/ however.

I'm looking for a workaround as well. If I find one, I'll report back.
You can work around this by putting disableOnClickOutside in a setTimeout.

componentDidMount() {
    setTimeout(()=>this.props.disableOnClickOutside(), 0);
}

A Lot of Static Elements

Hey,

Just out of curiosity, thnk of a Page with lots of Components - which are all Mounted already.
Every single Component uses one Mixin wheter i clicked outside a Dropdown - or not...

For each single Mouseclick on the Page, each Event is emitted and therefore every Function from those Child Components is executed - correct me if i'm wrong...

Wouldn't it be more efficient - memory wise - to attach the Event, only when i need it?

Deprecate Mixins?

Hey there,
I need this behaviour in several part of our app but I don't want to drag in a dependency on mixins, since they're not gonna be supported anymore.

I was about to write another component to handle that in a declarative fashion, but maybe you would like to have a PR here and move away from mixins?

UglifyJS warnings

Hi, there are some warnings in your code:

Condition always true [./~/react-onclickoutside/index.js:16,0]
Dropping unreachable code [./~/react-onclickoutside/index.js:21,3]

package strategy requiring 'react' will cause second copy of react to be loaded in some environments

Line 18: module.exports = factory(require('react')); will cause a second, possibly conflicting, version of React to be loaded in some project environments (I'll speak for mine only, where I'm requiring 'react/addons' in my source code).

I have fixed this locally in the following ways:
a) changing line 18 in react-onlclickoutside's index.js to read 'window.React || require('react'),
b) adding browserify-shim to react-onclickoutside's package.json file and setting the shim config to:
"browserify-shim": { "react": "global:React" } (note: this also requires dependency on browserify and setting the shim as a browserify transform).

I know that this is a common mixin pattern (and is required for using React's findDOMNode() accessor), so unsure if I'm missing a more obvious solution on my end?

JSX syntax usage

Hi there, I'm using this way of writing React and I'm trying to access the click outside functionality. Could you please suggest how to do it in this case:

import React from 'react';
import OnClickOutside from 'react-onclickoutside';

export default class Menu extends React.Component {

    constructor(props){
        super(props);
    }


    render() {

        return (
            <OnClickOutside>
                <ul>
                    <li>Test 1</li> 
                    <li>Test 2</li> 
                    <li>Test 3</li> 
                </ul>
            </OnClickOutside>
        );
    }


    handleClickOutside(event) {
        console.log('Clicked outside.');
    }
}

HOC not working

Hi,
I am trying to use the onclickoutside functionality via the HOC. Here is my (shortened) code:

import React, { Component, PropTypes } from 'react';
import listensToClickOutside from 'react-onclickoutside/decorator';

class FilterInput extends Component {

  ...

  handleClickOutside (event) {
    console.log('outside');
  }

  ...

}

export default listensToClickOutside(FilterInput);

But the handleClickOutside function is never called. Am I missing something?

Best,
Basti

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.