Check out this simple shopping cart demo:
http://plnkr.co/edit/CHt2iNSRJAJ6OWs7xmiP?p=preview
A user can pick a veggie and a fruit, and it will be added into
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:
<template>
<div>
<h1>{{title}}</h1>
<small>{{datetime}}</small>
</div>
</template>
<script>
export default {
props: {
title: String
},
data() {
return {
datetime: new Date()
}
}
}
</script>
<template>
<div>
<h3>{{title}}</h3>
<h6>{{datetime}}</h6>
</div>
</template>
<script>
export default {
props: {
title: String
},
data() {
return {
datetime: new Date()
}
}
}
</script>
after:
<template>
<div>
<h1>{{title}}</h1>
<small>{{datetime}}</small>
</div>
</template>
<script>
import shared from "./shared.js";
export default Object.assign({}, shared);
</script>
<template>
<div>
<h3>{{title}}</h3>
<h6>{{datetime}}</h6>
</div>
</template>
<script>
import shared from "./shared.js";
export default Object.assign({}, shared);
</script>
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);
}
I found this technique to be more simple/satisfactory, as I prefer composition over inheritance:
export default {
foo: function() { alert("foo!") }
}
<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
withthis.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.