Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I share a method between components in Vue.js?

People also ask

How do I call a Vue method from another component?

Call one method, apparently any method of a component from any other component. Just add a $on function to the $root instance and call form any other component accessing the $root and calling $emit function.

How do I share data between Vue components?

There are only three different ways to share data across the VueJs components, it depends on you which technique is better for you to solve your problem. Using props share data from parent to child. Using Event Emitting custom events to share data from child to parent.

How do you call a component method from parent Vue?

To call a method in a child component with Vue. js, we can pass in a prop from the parent component to its child. Then in the child component, we watch the prop's value and run the method we want. in the child component to register the testProp prop and add the sayHello method.

How do I switch between Vue components?

You need to bind the value into the component and then emit a new value to the parent when you click a link. If you emit the event input and bind the value value , then you can use v-model .


I found this technique to be more simple/satisfactory, as I prefer composition over inheritance:

src/shared.js

export default {
  foo: function() { alert("foo!") }
}

src/yourcomponent.vue

<template>...</template>

<script>
  import shared from './shared'

  export default {
    created() { 
      this.foo = shared.foo // now you can call this.foo() (in your functions/template)
    }
  }
</script>

This will also allow you to write Vue-agnostic tests.

NOTE: if you need foo to run in Vue-scope replace this.foo = shared.foo with this.foo = shared.foo.bind(this)


Option 1

One approach for sharing your method across components is to use a mixin. Here's a cartMixin that contains a selectProduct method:

var cartMixin = {
  methods: {
    selectProduct: function (product) {
      var cart = this.cart
      for(p in cart){
          if (cart[p]["type"] == product.type){
             console.log("We already got a "+ product.type +"!, Let's remove " + cart[p]["name"] + " and add in " + product["name"]);
             this.cart.$remove(cart[p])
          }
      }
      console.log("Adding " + product.name + " to cart.");
      var productName = product.name
      var cartProduct = {name: product.name, type: product.type}
      this.cart.push(cartProduct)
    }
  }
};

You can reference this in each component like this:

var Vegetable = Vue.extend({
    template: '#vegetable',
    mixins: [cartMixin],
    data: function(){
        return sourceOfTruth
    }
})

... and then use it in your templates like this:

<li v-for="product in food | showOnly 'fruit'" @click="selectProduct(product)">
  {{product.name}}
</li>

Here's a fork of your Plunker.

Option 2

After thinking about this some more, another option you might consider is to create a base Product component and extend that to create your Fruit and Vegetable components. You would then put your common functionality in the base component.

var Product = Vue.extend({
  data: function(){
      return sourceOfTruth
  },
  methods: {
    selectProduct: function (product) {
      var cart = this.cart
      for(p in cart){
          if (cart[p]["type"] == product.type){
             console.log("We already got a "+ product.type +"!, Let's remove " + cart[p]["name"] + " and add in " + product["name"]);
             this.cart.$remove(cart[p])
          }
      }
      console.log("Adding " + product.name + " to cart.");
      var productName = product.name
      var cartProduct = {name: product.name, type: product.type}
      this.cart.push(cartProduct)
    }
  }
})

var Vegetable = Product.extend({
  template: '#vegetable',
});
var Fruit = Product.extend({
  template: '#fruit',
});

Here's a Plunker with this approach.

Given that your Fruit and Vegetable templates are so similar, you might be able to take this idea even further and use a common template from the base component.


If you are trying to share the same component logic between or along multiple vue template and layout, you can simply try this approach below:

before:

a.vue

<template>
  <div>
     <h1>{{title}}</h1>
     <small>{{datetime}}</small>
  </div>
</template>

<script>
export default {
  props: {
    title: String
  },
  data() {
    return {
      datetime: new Date()
    }
  }
}
</script>

b.vue

<template>
  <div>
     <h3>{{title}}</h3>
     <h6>{{datetime}}</h6>
  </div>
</template>

<script>
export default {
  props: {
    title: String
  },
  data() {
    return {
      datetime: new Date()
    }
  }
}
</script>

after:

a.vue

<template>
  <div>
     <h1>{{title}}</h1>
     <small>{{datetime}}</small>
  </div>
</template>

<script>
import shared from "./shared.js";
export default Object.assign({}, shared);
</script>

b.vue

<template>
  <div>
     <h3>{{title}}</h3>
     <h6>{{datetime}}</h6>
  </div>
</template>

<script>
import shared from "./shared.js";
export default Object.assign({}, shared);
</script>

shared.js

export default {
  props: {
    title: String
  },
  data() {
    return {
      datetime: new Date()
    }
  }
}


You can put the method in your root Vue instance and then dispatch an event from the child instance when a veggie is selected, or when a fruit is selected. Events look for a handler on their parent component, and if they don't find an event handler they keep going up the chain until they do. So on your root instance:

events: {
    'choose-fruit':function(fruit){

        //handle the choosing of fruit

    }
}

Then on the child instance:

selectFruit: function(product){

    this.$dispatch('choose-fruit', product);

}