5

How do I call the method from another component in this scenario? I would like to load additional pice of data from the API once the button is clicked in the component 1 to the component 2.

Thanks

Here are my two components in the seperate files:

compbutton.vue

<template>
    <div>
        <a href v-on:click="buttonClicked">Change Name</a>
    </div>
</template>

<script>
    export default {
        name: 'compbutton',
        methods: {
            buttonClicked: function () {
                //call changeName here
            }
        }
    }
</script>

compname.vue

<template>
    <div>{{name}}</div>
</template>

<script>
    export default {
        name: 'compname',
        data: function () {
            return {
                name: 'John'
            }
        },
        methods: {
            changeName: function () {
                this.name = 'Ben'
            }
        }
    }
</script>
4
  • 1
    Store the data in a parent. Pass that data down to compname.vue as a prop. Make compbutton.vue emit an event on click, which the parent listens to. Change the data in the parent. compname.vue will receive the updated value. Commented Jan 5, 2018 at 6:34
  • Could you show me on my example? Commented Jan 5, 2018 at 6:35
  • 5
    Can you try implementing my suggestion first? I'll be glad to help after that. Here's the relevant docs. vuejs.org/v2/guide/components.html#Passing-Data-with-Props | vuejs.org/v2/guide/… Commented Jan 5, 2018 at 6:38
  • @Ben is compbutton.vue the parent component? Commented Jan 5, 2018 at 8:57

3 Answers 3

6

You can name the component and then $ref to the method from another componenent.

compbutton.vue

<template>
  <div>
    <a href v-on:click="buttonClicked">Change Name</a>
  </div>
</template>

<script>
export default {
  name: "compbutton",
  methods: {
    buttonClicked: function() {
      //call changeName here
      this.$root.$refs.compname_component.changeName();
    }
  }
};
</script>

compname.vue

<template>
  <div>{{name}}</div>
</template>

<script>
export default {
  name: "compname",
  data: function() {
    return {
      name: "John"
    };
  },
  methods: {
    changeName: function() {
      this.name = "Ben";
    }
  },
  created() {
    // set componenent name
    this.$root.$refs.compname_component = this;
  }
};
</script>
Sign up to request clarification or add additional context in comments.

Comments

3

Alternative answer: you can pass the function you want the child to invoke as a prop from the parent component. Using your example:

compbutton.vue

<template>
    <div>
        <a href v-on:click="buttonClicked">Change Name</a>
    </div>
</template>

<script>
    export default {
        name: 'compbutton',
        props: {
            clickHandler: {
                type: Function,
                default() {
                    return function () {};
                }
            }
        },
        methods: {
            buttonClicked: function () {
                this.clickHandler(); // invoke func passed via prop
            }
        }
    }
</script>

compname.vue

<template>
    <div>{{name}}</div>
    <compbutton :click-handler="changeName"></compbutton>
</template>

<script>
    export default {
        name: 'compname',
        data: function () {
            return {
                name: 'John'
            }
        },
        methods: {
            changeName: function () {
                this.name = 'Ben'
            }
        }
    }
</script>

Note, in your example, it doesn't appear where you want the 'compbutton' component to be rendered, so in the template for compname.vue, thats been added as well.

Comments

2

You can use a service as a go-between. Usually, services are used to share data but in javascript functions can be treated like data also.

The service code is trivial, just add a stub for the function changeName

changeName.service.js

export default {
  changeName: function () {}
}

To have services injected into the components, you need to include vue-injector in the project.

npm install --save vue-inject
or
yarn add vue-inject

and have a register of services,

injector-register.js

import injector from 'vue-inject';

import ChangeNameService from '@/services/changeName.service'

injector.service('changeNameService', function () { 
  return ChangeNameService 
});

then in main.js (or main file may be called index.js), a section to initialize the injector.

import injector from 'vue-inject';
require('@/services/injector-register');
Vue.use(injector);

Finally, add the service to the component dependencies array, and use the service

compname.vue

<script>
  export default {
    dependencies : ['changeNameService'],
    created() {
      // Set the service stub function to point to this one
      this.changeNameService.changeName = this.changeName;
    },
    ...

compbutton.vue

<script>
  export default {
    dependencies : ['changeNameService'],
    name: 'compbutton',
    methods: {
       buttonClicked: function () {
         this.changeNameService.changeName();
       }
    }
    ...

Add a # to the button href to stop page reloads

<a href="#" v-on:click="buttonClicked">Change Name</a>

See the whole thing in CodeSandbox

1 Comment

It is indeed, I tend to find that with Vue - simple bits but in a lot of places. Injection is the officially correct way to do it (I feel obliged to present the pattern), but you might find it works with simple imports of the service as well. Don't forget, injection makes unit testing go a lot easier.

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.