Ember, mixin to detect click outside of view/component
I'm writing a Mixin to handle when user clicks outside of a view/component.
This is the mixin:
App.ClickElsewhereMixin = Ember.Mixin.create({
  onClickElsewhere: Ember.K,
  didRender: function() {
    this._super.apply(this, arguments);
    return $(document).on('click', this.get('onClickElsewhere'));
  },
  willDestroyElement: function() {
    this._super.apply(this, arguments);
    $(document).off('click', this.get('onClickElsewhere'));
  },
});
I use it in my component:
onClickElsewhere: function() {
    this.send('exitEditMode');
},
But when I run it, I get:
TypeError: this.send is not a function
 How can I keep the this context?  
Solution:
just to make it easier for the reader, here the working Mixin:
App.ClickElsewhereMixin = Ember.Mixin.create({
  onClickElsewhere: Ember.K,
  setupListener: Ember.on('didRender', function() {
    // Set an event that will be fired when user clicks outside of the component/view
    return $(document).on('click', $.proxy(this.get('onClickElsewhere'), this));
  }),
  removeListener: Ember.on('willDestroyElement', function() {
    // Clean the previously defined event to keep events stack clean
    return $(document).off('click', $.proxy(this.get('onClickElsewhere'), this));
  }),
});
The current answer doesn't check whether the click was actually outside of the element – a click on the component will also trigger the callback.
Here's an updated version:
export default Ember.Mixin.create({
  onOutsideClick: Ember.K,
  handleOutsideClick: function(event) {
    let $element = this.$();
    let $target = $(event.target);
    if (!$target.closest($element).length) {
      this.onOutsideClick();
    }
  },
  setupOutsideClickListener: Ember.on('didInsertElement', function() {
    let clickHandler = this.get('handleOutsideClick').bind(this);
    return Ember.$(document).on('click', clickHandler);
  }),
  removeOutsideClickListener: Ember.on('willDestroyElement', function() {
    let clickHandler = this.get('handleOutsideClick').bind(this);
    return Ember.$(document).off('click', clickHandler);
  })
});
Greg answer have a mistake, that makes removing the clickHandler event not working. Which means that your clickevent will fire even if you destroy the component.
Here is proper version
import Ember from 'ember';
export default Ember.Mixin.create({
    onOutsideClick: Ember.K,
  handleOutsideClick: function(event) {
    let $element = this.$();
    let $target = $(event.target);
    if (!$target.closest($element).length) {
      this.onOutsideClick();
    }
  },
  setupOutsideClickListener: Ember.on('didInsertElement', function() {
    let clickHandler = this.get('handleOutsideClick').bind(this);
    return Ember.$(document).on('click', clickHandler);
  }),
  removeOutsideClickListener: Ember.on('willDestroyElement', function() {
    let clickHandler = this.get('handleOutsideClick').bind(this);
    return Ember.$(document).off('click', Ember.run.cancel(this, clickHandler));
  })
});
The ember way of doing it is Ember.run.bind. This takes care of binding and the run loop.
App.ClickElsewhereMixin = Ember.Mixin.create({
  onClickElsewhere: Ember.K,
  setupListener: Ember.on('didRender', function() {
    this.set('clickHandler', Ember.run.bind(this, this.onClickElsewhere));
    Ember.$(document).click(this.get('clickHandler'));
  }),
  removeListener: Ember.on('willDestroyElement', function() {
    Ember.$(document).off('click', this.get('clickHandler'));
  }),
});
