title: Trigger components methods when click elsewhere
body: <p>I've a HeaderSubmenu component which can show/hide a drop-down menu if a button is clicked. Okay, but now I try to find a good solution to make that if the user clicks anywhere in the app but not on this drop-down menu, it hides.</p>
  
  <p>I'm using Vue 2.3.3 with Vuex and VueRouter.</p>
  
  <p>my App entry point :</p>
  
  <pre><code>'use strict';
  
  import Vue from 'vue';
  import VueRouter from 'vue-router';
  import Vuex from 'vuex';
  
  Vue.use(VueRouter);
  Vue.use(Vuex);
  
  import store_data from 'store';
  import {router} from 'routes';
  
  import App from 'app.vue';
  
  var store = new Vuex.Store(store_data);
  
  new Vue({
    el: '#app',
    store,
    router: router,
    render: function (createElement) {
      return createElement(App)
    }
  })
  </code></pre>
  
  <p>template of <code>HeaderSubmenu</code> component :</p>
  
  <pre><code>&lt;template&gt;
    &lt;li class="header-submenu"&gt;
      &lt;!-- button to show/hide the drop-down menu --&gt;
      &lt;header-link v-bind="$props" :href="to ? false : '#'" @click.native="toggleMenu()"&gt;
        &lt;slot name="item"&gt;&lt;/slot&gt;
      &lt;/header-link&gt;
      &lt;!-- drop-down menu --&gt;
      &lt;ul class="submenu-list" :class="{'open': open, 'animated': animated}" @animationend="displaynone()"&gt;
        &lt;slot&gt;&lt;/slot&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
  &lt;/template&gt;
  </code></pre>
  
  <p>This component is somewhere in my app, and I want to call his <code>toggleMenu()</code> method when the users clicks elsewhere than on the <code>&lt;ul class="submenu-list"&gt;</code>.</p>
  
  <p>I thought of a global event bus where my drop-down menu should be "registred" and detects on a global @click event on my App. If the registered menu is not the element clicked we'd call his <code>toggleMenu()</code> method if not.
  (Ideally I could register other elements which have the same behaviour.)</p>
  
  <p>... But I don't master vue event system at all.
  How can check if an event is not on some element ?
  I've no idea of how to achieve this. Can you help me ? Thank you !</p>
  
  <p>====== EDIT ======</p>
  
  <p>With the help of Bert Evans I used this custom directive :</p>
  
  <pre><code>// directive-clickoutside.js
  export default {
    bind(el, binding, vnode) {
      el.event = function (event) {
        // here I check that click was outside the el and his childrens
        if (!(el == event.target || el.contains(event.target))) {
          // and if it did, call method provided in attribute value
          vnode.context[binding.expression](event);
        }
      };
      document.body.addEventListener('click', el.event)
    },
    unbind(el) {
      document.body.removeEventListener('click', el.event)
    },
  };
  
  // main.js
  import clickout from 'utils/directive-clickoutside';
  Vue.directive('clickout', clickout);
  </code></pre>
  
  <p>I used this in my component template :</p>
  
  <pre><code>// HeaderSubmenu component
  &lt;template&gt;
    &lt;li class="header-submenu"&gt;
      &lt;!-- élément du header servant à ouvrir le sous-menu --&gt;
      &lt;header-link v-bind="$props" :href="to ? false : '#'" @click.native="toggle()"&gt;
        &lt;slot name="item"&gt;&lt;/slot&gt;
      &lt;/header-link&gt;
      &lt;!-- sous-menu --&gt;
      &lt;ul class="submenu-list" :class="{'open': open, 'animated': animated}" @animationend="displaynone()" v-clickout="hide()"&gt;
        &lt;slot&gt;&lt;/slot&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
  &lt;/template&gt;
  </code></pre>
  
  <p>But this code fails when I click anywhere on the page :</p>
  
  <pre><code>Uncaught TypeError: n.context[e.expression] is not a function
      at HTMLBodyElement.t.event (directive-clickoutside.js:7)
  </code></pre>
  
  <p>Where is the problem ?</p>