Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename "action" handler to "onClickOutside" #47

Merged
merged 6 commits into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 9 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,26 @@

A component and mixin for detecting clicks happened outside the element.


## Usage
## Installation

From within your ember-cli project directory install the addon:

```bash
ember install ember-click-outside
```

Then:
## Usage

**As a component**
### As a component

```hbs
{{#click-outside action=(action "someAction")}}
{{#click-outside onClickOutside=(action "someAction")}}
Your HTML...
{{/click-outside}}
```

```js
...
...
actions: {
// Called on click outside
someAction(e /* click event object */) {
Expand All @@ -36,14 +35,14 @@ If you wish to exclude certain elements from counting as outside clicks, use
the `except-selector` attribute:

```hbs
{{#click-outside action=(action "someAction") except-selector=".some-selector"}}
{{#click-outside onClickOutside=(action "someAction") except-selector=".some-selector"}}
Your HTML...
{{/click-outside}}
```

**As a mixin**
### As a mixin

In fact, here is a simplified of implementation of the above component...
In fact, here is a simplified version of the implementation of the component above:

```js
import Component from '@ember/component';
Expand All @@ -52,10 +51,8 @@ import { next } from '@ember/runloop';
import ClickOutsideMixin from 'ember-click-outside/mixin';

export default Component.extend(ClickOutsideMixin, {
layout,

clickOutside(e) {
this.get('action')(e);
this.get('onClickOutside')(e);
},

_attachClickOutsideHandler: on('didInsertElement', function() {
Expand All @@ -66,7 +63,6 @@ export default Component.extend(ClickOutsideMixin, {
this.removeClickOutsideListener();
})
});

```

**Note:** You should almost always call `this.addClickOutsideListener` inside
Expand Down Expand Up @@ -103,26 +99,3 @@ export default Component.extend(ClickOutsideMixin, {
For every click in the document, `ember-click-outside` will check if the click target is outside of its component, and trigger the provided action/callback if so.

If the click target cannot be found in the document (probably because it has been deleted before `ember-click-outside` detected the click), no action/callback is triggered, since we cannot check if it is inside or outside of the component.

## Installation

* `git clone <repository-url>` this repository
* `cd ember-click-outside`
* `yarn install`

## Running

* `ember serve`
* Visit your app at [http://localhost:4200](http://localhost:4200).

## Running Tests

* `yarn test` (Runs `ember try:each` to test your addon against multiple Ember versions)
* `ember test`
* `ember test --server`

## Building

* `ember build`

For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/).
18 changes: 14 additions & 4 deletions addon/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,32 @@ import Component from '@ember/component';
import { next, cancel } from '@ember/runloop';
import { closest } from './utils';
import { get } from '@ember/object';
import { deprecatingAlias } from '@ember/object/computed';

export default Component.extend(ClickOutsideMixin, {
'except-selector': deprecatingAlias('exceptSelector', {
id: 'ember-click-outside.kebab-cased-props',
until: '2.0.0'
}),

action: deprecatingAlias('onClickOutside', {
id: 'ember-click-outside.action-prop',
until: '2.0.0'
}),

clickOutside(e) {
if (this.isDestroying || this.isDestroyed) {
return;
}

const exceptSelector = get(this, 'except-selector');
const exceptSelector = get(this, 'exceptSelector');
if (exceptSelector && closest(e.target, exceptSelector)) {
return;
}

let action = get(this, 'action');
if (typeof action === 'function') {
action(e);
let onClickOutside = get(this, 'onClickOutside');
if (typeof onClickOutside === 'function') {
onClickOutside(e);
}
},

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"ember-export-application-global": "^2.0.0",
"ember-load-initializers": "^1.0.0",
"ember-maybe-import-regenerator": "^0.1.6",
"ember-qunit-assert-helpers": "^0.2.2",
"ember-resolver": "^4.0.0",
"ember-source": "~3.0.0",
"ember-source-channel-url": "^1.0.1",
Expand Down
67 changes: 61 additions & 6 deletions tests/integration/components/click-outside-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module('click-outside', 'Integration | Component | click outside', function(hook
await render(hbs`
<div class="outside">Somewhere, over the rainbow...</div>

{{#click-outside action=(action didClickOutside)}}
{{#click-outside onClickOutside=(action didClickOutside)}}
<div class="inside">We're in</div>
{{/click-outside}}
`);
Expand All @@ -35,7 +35,7 @@ module('click-outside', 'Integration | Component | click outside', function(hook
});
});

test(`it doesn't throw without an action handler`, async function(assert) {
test(`it doesn't throw without an onClickOutside handler`, async function(assert) {
assert.expect(0);

await render(hbs`
Expand Down Expand Up @@ -63,7 +63,7 @@ module('click-outside', 'Integration | Component | click outside', function(hook
Somewhere, under the rainbow...
</div>

{{#click-outside except-selector=".except-outside" action=(action didClickOutside)}}
{{#click-outside exceptSelector=".except-outside" onClickOutside=(action didClickOutside)}}
{{/click-outside}}
`);

Expand All @@ -78,7 +78,39 @@ module('click-outside', 'Integration | Component | click outside', function(hook
await click('.except-outside');
});
});


test('deprecated `except-selector` still works', async function(assert) {
assert.expect(2);

this.set('didClickOutside', ()=> {
assert.ok('`didClickOutside` fired only once');
});

await render(hbs`
<div class="outside">Somewhere, over the rainbow...</div>

<div class="except-outside">
Somewhere, under the rainbow...
</div>

{{#click-outside except-selector=".except-outside" onClickOutside=(action didClickOutside)}}
{{/click-outside}}
`);

// It's important to fire the actions in the next run loop. Failing to do so
// would make the outside click not to fire. The reason for this is more
// often than not the component is rendered as a result of some user
// interaction, mainly a click. If the component attached the outside click
// event handler in the same loop, the handler would catch the event and send
// the action immediately.
await next(async ()=> {
await click('.outside');
await click('.except-outside');
});

assert.expectDeprecation();
});

test('handle removed DOM element outside', async function(assert) {
assert.expect(1);

Expand All @@ -96,13 +128,36 @@ module('click-outside', 'Integration | Component | click outside', function(hook
{{else}}
<div class="outside" {{action "toggleFlag"}}>Yellow</div>
{{/if}}
{{#click-outside action=(action didClickOutside)}}

{{#click-outside onClickOutside=(action didClickOutside)}}
{{/click-outside}}
`);

await next(async () => {
await click('.outside');
});
});

test('`action` handler is still valid', async function(assert) {
assert.expect(2);

this.setProperties({
onClickOutside: () => assert.ok('`onClickOutside` fired once')
});

await render(hbs`
<div class="outside">Somewhere, over the rainbow...</div>

{{#click-outside action=(action onClickOutside)}}
<div class="inside">We're in</div>
{{/click-outside}}
`);

await next(async ()=> {
await click('.inside');
await click('.outside');
});

assert.expectDeprecation();
});
});
Loading