Johannes
Johannes

Reputation: 1488

Capture all click events inside Vue application

I need to capture all click events triggered by the user inside my Vue.js application. My first step was to add an onclick listener to the #app div:

<div id="app" @click="onClickApp"></div>
// ...
<script>
  export default {
    methods: {
      onClickApp() {
        // increment counter in vuex store
      }
   }
</script>

This captures all click events happening directly inside the App component. The issue is that I'm using a Bootstrap Modal (provided via BootstrapVue) and I need to capture the clicks inside it as well. This is not working at the moment, even if I set another @click listener on the <b-modal></b-modal> component (syntax for vue-cli).

This is what I also tried (in main.js):

new Vue({
  router,
  store,
  render: h => h(App),
  mounted: function() {
    this.$el.addEventListener('click', this.onClickVue)
  },
  beforeDestroy: function () {
    this.$el.removeEventListener('click', this.onClickVue)
  },
  methods: {
    onClickVue: function (e) {
      this.$store.commit(mutationTypes.INCREMENT_CLICKS)
    }
  });

Same problem, clicks inside the Bootstrap Modals are not firing a click event.

Upvotes: 5

Views: 9011

Answers (4)

Matt Oestreich
Matt Oestreich

Reputation: 8548

I could only get this to work by using the mouseup event..

CodePen mirror: https://codepen.io/oze4/pen/PgKWRW?editors=1010

new Vue({
  el: "#app",
  data: {
    modalShow: false
  },
  mounted() {
    document.addEventListener("mouseup", e => {
      let m = `x: ${e.clientX} | y: ${e.clientY}`;
      console.log(m);
    })
  }
});
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.min.js"></script>
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet" />

<div id="app">
  <div style="margin: 5px 0px 0px 40px">
    <b-button @click="modalShow = !modalShow">Open Modal</b-button>
    <b-modal v-model="modalShow">Hello From Modal!</b-modal>
  </div>
</div>

Upvotes: 4

Marvin Irwin
Marvin Irwin

Reputation: 1030

I couldn't find a way to test with Bootstrap Vue, but this might do.

TLDR: Create a plugin which will run whenever any of your components are instantiated. Put a listener on the root element.

https://codesandbox.io/s/kxwz85pl65

const MyPlugin = {
  install(Vue, options) {
    Vue.mixin({
      mounted() {
        setTimeout(() => {
          let cb = this.$root.$el.onclick;
          this.$root.$el.onclick = (e) => {
            alert("element clicked");
            if (cb) {
              cb(e);
            }
          };
        }, 10);
      }
    });
  }
};

EDIT:

As of writing this Vue Bootstrap doesn't seem to allow click events for the modal itself, though elements inside of it can be clicked.

https://codesandbox.io/embed/kxwz85pl65

EDIT again, you can use set timeout if you really want to. It's a bit of a hack though.

Upvotes: 0

LJD
LJD

Reputation: 496

A better answer is just adding ev to onClickApp, so do onClickApp(ev) inside your methods.

Now, you have access to the click event.

Upvotes: 1

Adam Orłowski
Adam Orłowski

Reputation: 4484

This should work ;-)

- <div id="app" @click="onClickApp"></div>
+ <div id="app"></div>
// ...
<script>
  export default {
    methods: {
      onClickApp() {
        // increment counter in vuex store
      }
   },
+  mounted() {
+    window.document.addEventListener('click'), this.onClickApp)
+  },
+  beforeDestroy() {
+    window.document.removeEventListener('click'), this.onClickApp)
+  }
</script>

Upvotes: 0

Related Questions