0

I am trying to use a method from on of my vue components in another vue component. I have implemented a solution below, however, I think there can be something more reusable.

Here is my problem: I want to call a method from one vue component (which is registered in the instance) in another component inside of it's template in a @click (or alternative) inside of a v-for.

This is my current solution:

Vue Component 1 (this is the component making the call):

Vue.component('person-list', {
    props: ['user_id', 'token'],
    template: '<div>' +
        '<ul>' +
        '<li v-for="person in persons" :data-id="person.lk_ID" 
class="someItems-list-item">{{ person.name }}</li>' +
        '</ul>' +
        '</div>',
    data: function(){
        return {
            persons: null,
        }
    },
    methods: {
        //some code
    },
    mounted: function(){
        console.log('mounted list');
    }
});

Vue Component 2

var someItems= Vue.component('someItems-items-list', {
    props: ['g_id', 'token'],
    template: '<div>' +
    '<ul>' +
    '<li v-for="item in someItems">{{ item.name }}</li>' +
    '</ul>' +
    '</div>',
data: function(){
    return {
        someItems: null,
    }
},
methods: {
    callFunction: function (ID = null){
        this.$http.post('route', {someID: ID, _token: this.token}).then(function(response){
            this.someItems= response.body.items;
        });
    },
},
mounted: function(){
    this.callFunction();
}
});

Instance

const app = new Vue({
    el: '#app',
    components: {
        'someItems-items-list': someItems,
    },
});

Solution in Jquery

$(document).on('click','.someItems-list-item',function () {
   app.$refs.someItems.callFunction($(this).data('id'));
});  

This solution works fine, and its not that much more code, but I think it would be cleaner and easier to maintain if I could call callFunction() like this:

Vue Component 1

template: '<div>' +
        '<ul>' +
        '<li v-for="person in persons" @click="app.$refs.someItems.callFunction(person.lk_ID)">{{ person.name }}</li>' +
        '</ul>' +
        '</div>',

However, when I try that, it says that app is undefined. I have also tried the above with this:

Vue Component 1

return {
        //other code,
        this.someItems: someItems,
    }

And then calling in @click="someItems.callFunction(1)" but it also does not work. All these components are inside of app.js. I am working with laravel,vue,jquery.

I feel that I may be missing something in terms of how to connect two vue components to each other, and have been unable to learn it from searching.

2
  • 1
    This answer could help you out Commented Jan 15, 2019 at 4:09
  • Also, @click="app.$refs.someItems..., should be $refs.someItems... Commented Jan 15, 2019 at 4:10

1 Answer 1

0

The recommended way to approach this in Vue is with emitting custom events or vuex. Seems like you're looking for the custom event approach. With this method, you would emit a custom event with a payload from component A, listen to that event in the parent component, and then update the prop of component B, and setup a watch in component B that would respond when the prop changes and call a method.

This article explains it well:

https://www.telerik.com/blogs/how-to-emit-data-in-vue-beyond-the-vuejs-documentation

The most important parts are:

//emit from component A
this.$emit('update-cart', item)

//setup listener in parent
<componentA @update-cart="updateCart">
updateCart(e) {
    this.cart.push(e);
    this.total = this.shoppingCartTotal;
  },

//setup componentB with prop from parent
<componentB :total="total">

//have watch in componentB
props: ['total'],
watch:{
  total:function(val){
    //call fn with new val
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.