Reputation: 481
In this codesandbox demo, the parent home
component has a child addItem
component. Parent's passes array (as prop) to the child and so the child is able to add item to the parent's list i.e. the normal way of passing data from parent -> child i.e. via props :fruitsArr="fruits"
.
Main.js
import Vue from "vue";
import VueRouter from "vue-router";
import App from "./App.vue";
import Home from "./components/Home.vue";
import addItem from "./components/addItem.vue";
Vue.use(VueRouter);
var router = new VueRouter({
mode: "history",
routes: [
{ path: "", component: Home, name: "Home" },
{
path: "/addItem",
component: addItem,
name: "Add Item"
}
]
});
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App)
}).$mount("#app");
App.vue
<template>
<div id="app">
<app-header></app-header>
<br>
<router-view></router-view>
</div>
</template>
<script>
import appHeader from "./components/common/appHeader";
export default {
name: "App",
components: {
appHeader
}
};
</script>
appHeader.vue
<template>
<ul class="nav nav-pills">
<router-link tag="li" to="/" active-class="active" exact>
<a>Home</a>
</router-link>
<router-link tag="li" to="/addItem" active-class="active">
<a>Add Item</a>
</router-link>
</ul>
</template>
Home.vue
<template>
<div>
<addItem :fruitsArr="fruits"/>
<h3>Fruits List</h3>
<ul>
<li v-for="(fruit, idx) in fruits" :key="idx">{{fruit}}</li>
</ul>
</div>
</template>
<script>
import addItem from "./addItem";
export default {
name: "App",
data() {
return {
fruits: ["Apple", "Mango", "Orange", "PineApple"]
};
},
components: {
addItem
}
};
</script>
addItem.vue
<template>
<div class="input-wrapper">
Enter Fruit Name:
<input type="text" v-model="fruitItem">
<button @click="addFruit">Add Fruit</button>
</div>
</template>
<script>
export default {
data() {
return {
fruitItem: ""
};
},
props: ["fruitsArr"],
methods: {
addFruit() {
this.fruitsArr.push(this.fruitItem);
}
},
};
</script>
The problem is when the child is visited directly using router-link
(vue-router) then parent's prop :fruitsArr="fruits"
is not available.
Can anybuddy tell me, how to or the correct way to pass parent's prop to the child when the current route is the child, such that child is able to add item to the parent's list. I'd prefer a solution WITHOUT using VueX or any other centralized store such as eventBus.
Thanks
Upvotes: 0
Views: 2464
Reputation: 29109
There are a couple of solutions.
You can use provide/inject to send data down the child hierarchy. This is the recommended way to share data from parent to non-immediate child
when the communication is only needed on a single parent-child branch
, and you do not want to go with Vuex
.
https://v2.vuejs.org/v2/api/#provide-inject
You can store items in the route's meta fields and initialize it in a navigation guard. Then it is available in all components.
https://router.vuejs.org/guide/advanced/navigation-guards.html
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
With that said, the Vue
way is to emit events up
and receive properties down
, so try to work with that architecture if your use-case allows.
Upvotes: 1
Reputation: 702
Steven Spungin`s answer is good. But you shall take into account that provide/inject data is not reactive.
That being said - you need to make some sort of centralized "source of truth". If you don't want to use Vuex - simpliest solution is to declare one more Vue instance and store your global data there. It would be reactive.
const myStore = new Vue({
data:{
fruits: ["Apple", "Mango", "Orange", "PineApple"]
}
})
export myStore;
and in your component
import {myStore} from 'somewhere';
//to use prop in your template - proxy it using computed prop
....
computed:{
fruits(){
return myStore.fruits;
}
}
....
Upvotes: 0