In this post, we’ll see how we can share the data from parent to child and vice-versa.
Passing data from parent to child component
Let’s say we have a user component and a display component. We’ll pass user details to the display component and the display component will display all the users data in a tabular format.
To pass the data to the child component we have to use the v-bind
or we can use the : (colon) shorthand.
<ResultsPanel :user-data="this.users" />
In the above code snippet, we are passing the users
array to ResultsPanel component with :user-data
binding. In the ResultsPanel.vue
file, we’ll define a property in the props object with the same name (userData) as we defined in the binding.
export default { data () { return {}; }, props: { userData: { type: Array, default: () => { return []; } } } }
Vue JS is smart enough to map data from kebab-case to camel case. So, the data passed to our :user-data
in the parent component will be captured in the userData
object in the props object in the child component.
Here’s the working example of User.vue and ResultsPanel.vue
<template> <ResultsPanel :user-data="this.users" /> </template> <script> import ResultsPanel from "./ResultsPanel.vue"; export default { components: { ResultsPanel }, data() { return { users: [ { id: 1, name: "Kevin", email: "[email protected]" }, { id: 2, name: "John", email: "[email protected]" }, { id: 3, name: "Matt", email: "[email protected]" } ] }; } }; </script>
<!-- ResultPanel.vue --> <template> <table border="1"> <thead> <tr> <td>User ID</td> <td>Username</td> </tr> </thead> <tr v-for="user in userData" :key="user.id"> <td>{{ user.id }}</td> <td>{{ user.name }}</td> </tr> </table> </template> <script> export default { name: 'ResultsPanel', data () { return { } }, props: { userData: { type: Array, default: () => { return []; } } } } </script>
In the above two code snippets, we passed data from the User component to the ResultsPanel with : (shorthand for v-bind). And in the ResultsPanel we’ve iterated over the users data and displayed it in the form of a table.
Here’s the output on code sandbox:
What happens if the child component does not have a proper props object?
If you did not declare a props object then vue will not show any errors in the console. Try this by removing the userData
or try editing it to a different name. You will not see any errors and of course you will not see any data displayed on the screen apart from the table headers.
Passing data from child component to parent (with $emit)
Let’s add admin rights to the user details in the above example. If the user already has admin rights the checkbox will be true otherwise it will not be checked.
If the user tries to check/uncheck we’ll restrict the action by passing information from child to parent with $emit
and perform necessary action.
Here’s the code for displaying admin checkbox in the ResultPanel
<table border="1"> <thead> <tr> <td>User ID</td> <td>Username</td> <td>Is Admin</td> </tr> </thead> <tr v-for="user in userData" :key="user.id"> <td>{{ user.id }}</td> <td>{{ user.name }}</td> <td> <input type="checkbox" :checked="user.isAdmin" @click="makeAdmin(user.id, $event)"> </td> </tr> </table>
When user tries to check/uncheck the box, we’ll invoke makeAdmin
method which will then emit the event back to the parent component (in our case its the user component).
Let’s see the makeAdmin
method.
methods: { makeAdmin(userId, event) { event.preventDefault(); this.$emit("editing-admin"); } }
With event.preventDefault()
we will prevent the checkbox from checking/unchecking.
With $emit
we will invoke the editing-admin
event on the parent component.
Now we are done with the child component setup.
To be able to fire our editing-admin
event that is raised from the child component we’ll have to create a method in the parent component.
Define an even listener on the ResultPanel
element like this in the parent component template.
<ResultsPanel :user-data="this.users" @editing-admin='editAdmin' />
Notice the event name here (@editing-admin
). This should match with the event that is emitted from the child (this.$emit("editing-admin")
).
Now, we define our method to capture the event emitted from the child component (editAdmin
).
methods: { editAdmin() { alert("You don't have permission to change the admin rights."); } }
For the purpose of this demo, I’ve used a simple alert to show the warning message here. You could do whatever is appropriate for your purpose.
What happens if there’s no event to capture the raised event with $emit?
Well, nothing. You don’t see any errors in the console if you don’t wire up the event to capture in the parent component.
Try removing the @editing-admin='editAdmin'
on the User.vue
the component in the demo. And after removing the click event binding try clicking the checkbox in the table. You should not see any alert now.
Karthik is a passionate Full Stack developer working primarily on .NET Core, microservices, distributed systems, VUE and JavaScript. He also loves NBA basketball so you might find some NBA examples in his posts and he owns this blog.