Component events in Vue

Published 2 weeks ago by Riotsmurf

I am having a problem binding events to elements in my vue component. I will give an example of my issue and maybe someone can help me out.

I have a file called test.vue and it has

<template>
  <div class="box">
    <div class="button" v-on:click="testMethod">Do something</div>
     <div class="box">
         <div class="columns">
             <div class="column">Column 1</div>
             <div class="column">Column 2</div>
             <div class="column">Column 3</div>
             <div class="column">Column 4</div>
             <div class="column">Column 5</div>
         </div>
       </div>
  </div>    
</template>

I have a javascript file called test.js that has

window.Vue = require('vue');

(function(){

    Vue.component('my-test', require('./components/test.vue'));
    new Vue({
        el: '#test',
        created: function() {
            console.log('Starting the testarino');
        }
        methods :{
            testMethod: function(){
               console.log("I did something yay!!");
            }
        }
    });
}());

my blade template looks like this

{{--Extend base layout--}}
@extends('layouts.app')

{{--Links and scripts--}}
@section('scripts')
  <script src="{{asset('js/test.js')}}" ></script>
@endsection

{{--Content--}}
@section('content')
  <div id="test">
    <my-test></my-test>
  </div>
@endsection

When i load the page i get this error in the console

[Vue warn]: Property or method "testMethod" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.

found in

---> <MyTest> at /var/www/html/resources/assets/js/components/test.vue
       <Root>
warn @ test.js:951
warnNonPresent @ test.js:2106
get @ test.js:2147
render @ test.js:404
Vue._render @ test.js:4600
updateComponent @ test.js:3010
get @ test.js:3353
Watcher @ test.js:3342
mountComponent @ test.js:3014
Vue$3.$mount @ test.js:8335
Vue$3.$mount @ test.js:10538
init @ test.js:3973
createComponent @ test.js:5619
createElm @ test.js:5562
createChildren @ test.js:5690
createElm @ test.js:5595
patch @ test.js:6078
Vue._update @ test.js:2886
updateComponent @ test.js:3010
get @ test.js:3353
Watcher @ test.js:3342
mountComponent @ test.js:3014
Vue$3.$mount @ test.js:8335
Vue$3.$mount @ test.js:10538
Vue._init @ test.js:4708
Vue$3 @ test.js:4793
(anonymous) @ test.js:92
module.exports @ test.js:105
__webpack_require__ @ test.js:20
(anonymous) @ test.js:10592
__webpack_require__ @ test.js:20
(anonymous) @ test.js:66
(anonymous) @ test.js:69
test.js:951 [Vue warn]: Invalid handler for event "click": got undefined

found in

---> <MyTest> at /var/www/html/resources/assets/js/components/test.vue
       <Root>
Best Answer (As Selected By Riotsmurf)
andonovn

The testMethod has to be moved from the root instance to the component. In other words, add the following to your test.vue file:

<script>
    export default {
        methods: {
            testMethod() {
               console.log("I did something yay!!");
            }
        }
    }
</script>
  • I changed the testMethod declaration to ES6 syntax :) It's not a must, so you can bring it back if you are not comfortable with ES6.
andonovn

The testMethod has to be moved from the root instance to the component. In other words, add the following to your test.vue file:

<script>
    export default {
        methods: {
            testMethod() {
               console.log("I did something yay!!");
            }
        }
    }
</script>
  • I changed the testMethod declaration to ES6 syntax :) It's not a must, so you can bring it back if you are not comfortable with ES6.
Riotsmurf

@andonovn What if i wanted it to override the templates testMethod() with the

new Vue({
   methods:{
    testMethod(){
        console.log('Some different than normal stuff');
    }
   }
})
andonovn

@Riotsmurf That's not inheritance, you are not overriding anything. If you need to do something in the root, then just emit an event from the component and handle it in the root.

Here's the example:

  1. In your blade file (ie the root template) change <my-test></my-test> to <my-test something="testMethod()"></my-test>. This would mean when the my-test component emits an event called something you would trigger the testMethod() on the root.
  2. In your component's testMethod() add this.$emit('something'). That would trigger all the listeners for the something event. And we just created our in 1.

Basically, without touching anything else, that should log Some different than normal stuff in your console (ie triggering your root's testMethod)

That's the simplest way to communicate from child to parent. If you need something more complex, then refer to the Vue documentation because there are few other ways to achieve this.

Riotsmurf

@andonovn Thank you very much for coming back and explaining this. Helped a lot.

Sign In or create a forum account to participate in this discussion.