In this article, we learn Emit events from child components in Vue, as well as events from nested child components. We will do all this while avoiding a common anti-pattern model that Vue developers often do.
A core concept behind a lot of f Syrians and JavaScript libraries is the ability to encapsulate data and the user interface inside reusable module components. This is great for helping developers avoid repetitive scripts throughout the application. However, while the ability to contain the inner function of a component is excellent, a component will often need ways to communicate with external components or more specifically with other components.
We can send data down from a main component via properties. This is usually a fairly simple concept to grasp. But what can be said about sending data from a backup child component to its parent component?
At Vue, we initially had a bit of a hard time figuring out how to do this primarily because we felt that Vue’s documentation didn’t include this or could solve this problem thoroughly and Emit data can probably solve this problem.
1.Set up
We will use the Vue CLI to quickly set up some of the boilerplate code, as well as all the other nice things it brings, such as reloading the module, auto-compiling, etc.
We will try not to spend too much time setting up, because the focus here is to show you how to play Emit data, instead of showing you how to set up each step of the Shopping Cart application.
2.Event What is Emit?
In our case, the Emit data aims to “emit” the signal. Signal from a child component to notify a parent coponent that an event has taken place (for example, a click event). Typically, the parent component will then perform some kind of action, such as executing a function.
3. How to Emit data from a Child Component
Whenever the user clicks the Add to Cart button, we want the item in question to be added to our cart. This sounds simple. What we also need to remember is that, with a component-based application, each item in the store is its own component (the component’s name is Shop-Item
). When we click the button inside Shop-Item.vue
, it needs to re-emit data about its parent component for the shopping cart to be updated.
First we have the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <span class="token operator"><</span> <span class="token operator">!</span> <span class="token operator">--</span> Shop <span class="token operator">-</span> Item <span class="token punctuation">.</span> vue <span class="token operator">--</span> <span class="token operator">></span> <span class="token operator"><</span> template <span class="token operator">></span> <span class="token operator"><</span> div <span class="token keyword">class</span> <span class="token operator">=</span> <span class="token string">"Item"</span> <span class="token operator">></span> <span class="token operator"><</span> img <span class="token punctuation">:</span> src <span class="token operator">=</span> <span class="token string">"item.imageSrc"</span> <span class="token punctuation">:</span> alt <span class="token operator">=</span> <span class="token string">"item.name"</span> <span class="token keyword">class</span> <span class="token operator">=</span> <span class="token string">"ItemImage"</span> <span class="token operator">></span> <span class="token operator"><</span> div <span class="token keyword">class</span> <span class="token operator">=</span> <span class="token string">"ItemDetails"</span> <span class="token operator">></span> <span class="token operator"><</span> p <span class="token operator">></span> <span class="token operator"><</span> strong <span class="token operator">></span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> item <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> strong <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> p <span class="token operator">></span> <span class="token operator"><</span> p <span class="token operator">></span> Price <span class="token punctuation">:</span> <span class="token operator"><</span> strong <span class="token operator">></span> $ <span class="token punctuation">{</span> <span class="token punctuation">{</span> item <span class="token punctuation">.</span> price <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> strong <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> p <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token operator"><</span> button <span class="token keyword">class</span> <span class="token operator">=</span> <span class="token string">"Button"</span> @click <span class="token operator">=</span> <span class="token string">"addToCart(item)"</span> <span class="token operator">></span> Add To Cart <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> template <span class="token operator">></span> <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> name <span class="token punctuation">:</span> <span class="token string">'Shop-Item'</span> <span class="token punctuation">,</span> props <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'item'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token function">data</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> methods <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token function">addToCart</span> <span class="token punctuation">(</span> item <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> <span class="token function">$emit</span> <span class="token punctuation">(</span> <span class="token string">'update-cart'</span> <span class="token punctuation">,</span> item <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> <span class="token operator"><</span> style <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> style <span class="token operator">></span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <span class="token operator"><</span> <span class="token operator">!</span> <span class="token operator">--</span> App <span class="token operator">-</span> Item <span class="token punctuation">.</span> vue <span class="token operator">--</span> <span class="token operator">></span> <span class="token operator"><</span> template <span class="token operator">></span> <span class="token operator"><</span> div id <span class="token operator">=</span> <span class="token string">"app"</span> <span class="token operator">></span> <span class="token operator"><</span> section <span class="token keyword">class</span> <span class="token operator">=</span> <span class="token string">"Header"</span> <span class="token operator">></span> <span class="token operator"><</span> h1 id <span class="token operator">=</span> <span class="token string">"Fruiticious!"</span> <span class="token operator">></span> Fruiticious <span class="token operator">!</span> <span class="token operator"><</span> <span class="token operator">/</span> h1 <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">!</span> <span class="token operator">--</span> Cart component <span class="token operator">--</span> <span class="token operator">></span> <span class="token operator"><</span> shop <span class="token operator">-</span> cart <span class="token punctuation">:</span> cart <span class="token operator">=</span> <span class="token string">"this.cart"</span> <span class="token punctuation">:</span> total <span class="token operator">=</span> <span class="token string">"this.total"</span> @empty <span class="token operator">-</span> cart <span class="token operator">=</span> <span class="token string">"emptyCart"</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> shop <span class="token operator">-</span> cart <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> section <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">!</span> <span class="token operator">--</span> Item component <span class="token operator">--</span> <span class="token operator">></span> <span class="token operator"><</span> shop <span class="token operator">-</span> item v <span class="token operator">-</span> <span class="token keyword">for</span> <span class="token operator">=</span> <span class="token string">"item in this.items"</span> <span class="token punctuation">:</span> item <span class="token operator">=</span> <span class="token string">"item"</span> <span class="token punctuation">:</span> key <span class="token operator">=</span> <span class="token string">"item.id"</span> @update <span class="token operator">-</span> cart <span class="token operator">=</span> <span class="token string">"updateCart"</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> shop <span class="token operator">-</span> item <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> template <span class="token operator">></span> <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> name <span class="token punctuation">:</span> <span class="token string">'app'</span> <span class="token punctuation">,</span> <span class="token function">data</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> items <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id <span class="token punctuation">:</span> <span class="token number">205</span> <span class="token punctuation">,</span> name <span class="token punctuation">:</span> <span class="token string">'Banana'</span> <span class="token punctuation">,</span> price <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">,</span> imageSrc <span class="token punctuation">:</span> Banana <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token punctuation">:</span> <span class="token number">148</span> <span class="token punctuation">,</span> name <span class="token punctuation">:</span> <span class="token string">'Orange'</span> <span class="token punctuation">,</span> price <span class="token punctuation">:</span> <span class="token number">2</span> <span class="token punctuation">,</span> imageSrc <span class="token punctuation">:</span> Orange <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token punctuation">:</span> <span class="token number">248</span> <span class="token punctuation">,</span> name <span class="token punctuation">:</span> <span class="token string">'Apple'</span> <span class="token punctuation">,</span> price <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">,</span> imageSrc <span class="token punctuation">:</span> Apple <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> cart <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> total <span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> methods <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token function">updateCart</span> <span class="token punctuation">(</span> e <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> cart <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> e <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> total <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> shoppingCartTotal <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">emptyCart</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> cart <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> total <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> |
Let’s go in more detail to the mentioned events.
We have a Button in Shop-Item.vue
:
1 2 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">class</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> Button <span class="token punctuation">"</span></span> <span class="token attr-name">@click</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> addToCart(item) <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> Add To Cart <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> |
Every item in the store (Banana, Orange, Apple) has this button. When it is clicked, our @click="addToCart(item)
is triggered. You can see that it takes the item
as a parameter (this is the entire item
object passed in <Shop-Item>
as prop.) When pressing the button
, it will activate the addToCart
function:
1 2 3 4 | <span class="token function">addToCart</span> <span class="token punctuation">(</span> item <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> <span class="token function">$emit</span> <span class="token punctuation">(</span> <span class="token string">'update-cart'</span> <span class="token punctuation">,</span> item <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
We see that this function uses this.$emit
. What does that mean? Well, simply Emit data is sending a signal. In this case, the signal is ‘update cart’, sent as a string. So basically, this.$emit
takes its first parameter string
. It can also accept a second parameter, which usually takes the form of some data we want to send with it. This could be another string
, an integer
, a variable, an array
, or in our case, an object
.
But then how do we send the “update-cart” string
to notify our parent component that the shopping cart is up to date?
When we add our <shop-item> App.vue
to App.vue
, we also add a custom event listener to it to listen for the update-cart
event. In fact, it really looks like the @click
listener hears our event on the ' Thêm vào giỏ hàng '.
buttons ' Thêm vào giỏ hàng '.
1 2 3 4 5 6 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> shop-item</span> <span class="token attr-name">v-for</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> item in this.items <span class="token punctuation">"</span></span> <span class="token attr-name">:item</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> item <span class="token punctuation">"</span></span> <span class="token attr-name">:key</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> item.id <span class="token punctuation">"</span></span> <span class="token attr-name">@update-cart</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> updateCart <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> shop-item</span> <span class="token punctuation">></span></span> |
We see that here our custom event listeners are waiting for the update-cart
be triggered. And how to know when this happens? When the string 'update-cart'
is issued from inside Shop-Item.vue!
Finally, let’s see what happens when the @update-cart
listens for this event and activates the update cart function:
1 2 3 4 5 | <span class="token function">updateCart</span> <span class="token punctuation">(</span> e <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> cart <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> e <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> total <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> shoppingCartTotal <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
This simply takes an event parameter and pushes it to this.cart
array. The event that it takes is simply the item that we initially set as the second parameter when we call this.$emit
. You can also see that this.totalmm
is also updated to return the result of this.shoppingCartTotal
function. As such, it is a simple way for us to emit data from a child component to the parent components.