When we have nested components, we also need a mechanism to establish communication between them. If we want to send some data from parent component to child component we use props.

What if we want to notify something to the parent component after a certain action in the child Component?

In this tutorial let's try to figure this out using a simple example.

Let's say you are working on an application which has a lot of posts and user can perform like action on each post.

Like Component

Here is our Like Component.

Vue.component('like',{
    template: `<span><i @click="likeToggle" :class="[liked ? 'fa blue' : 'far']" class="like-button fa-thumbs-up"></i> {{liked ? 'Liked' : 'Like'}}</span>`,
    data(){
        return{
            liked: false,
        }
    },
    methods:{
        likeToggle(){
            this.liked = !this.liked;
        }
    }
});

The like component is very simple.

  • In its template, we have used a thumbs-up font awesome icon.
  • We have defined a single boolean data property named liked, which denotes if the button has been clicked.
  • Clicking on the icon invokes the likeToggle() method, which toggles the liked property.

You also need to include the following style rules to change the button color when liked.

       .blue{
            color: #0088cc;
        }
        .like-button:hover{
            color: #0088cc;
        }

Like is an independent component and can be used anywhere in the application with following element.

<like>&lt;/like>

And here is how the output looks like

[WP-Coder id="12"]

Post Component

Let's move a step ahead and design our Post, component. We'll use the Bootstrap Card component to design our Post component.

Also since we want the ability that a post can be liked, we will use the like component inside the Post component's template.

Vue.component('post',{
    template: `<div class="card" style="width: 18rem;">
                <div class="card-body">
                <h5 class="card-title">Post Title</h5>
                <h6 class="card-subtitle mb-2 text-muted">This is a sample post description</h6>
                <like></like>
                <br>Total Likes {{totalLikes}}
                </div>
            </div>`,

    data(){
        return{
            totalLikes: 0
        }
    },
});

Above is the code structure of the post component.

  • We have used a sample text in the Bootstrap card component.
  • We have also included like component in the template, that gives the user the ability to like the post.
  • We have included a single data property named totalLikes, which will denote how many likes this post has received.

You can generate as many post components in your HTML markup with the following markup.

<post></post>

Now, when the user clicks on the like button, we want it to send a notification to the post component that the user has clicked the like button. So, in turn, the post component now needs to increase the totalLikes count. But how do we achieve this communication?

Sending Communication from Child Component to Parent.

We now want to send communication from like component (child) to Post component ( parent) whenever the user likes, or unlikes the button.

We can implement this using a custom event.

Let's modify the likeToggle method of the like component.


...
methods:{
    likeToggle(){
        this.liked = !this.liked;
        this.$emit('postLiked', (this.liked ? 1 : -1))
    }
}
...

We emit a custom event named postLiked whenever the like button is clicked, and we do it via this.$emit method.

  • The first parameter is the name of the event that we are emitting.
  • The second optional parameter any value that we want to send with the event. In our case, we send 1 if it's a like action and we send -1 if its unlike action.

Consider it like this.

Whenever the user is clicking on the like button. Thie like component is making an announcement by emitting an event. Now whatever component cares for that announcement can listen to it and make necessary adjustments on itself

Let's see how we can listen to the event announcement in our Post component.

        Vue.component('post',{
            template: `<div class="card" style="width: 18rem;">
                        <div class="card-body">
                        <h5 class="card-title">Post Title</h5>
                        <h6 class="card-subtitle mb-2 text-muted">This is a sample post description</h6>
                        <like @postLiked="onPostLiked"></like>
                        <br>Total Likes {{totalLikes}}
                        </div>
                    </div>`,

            data(){
                return{
                    totalLikes: 0
                }
            },

            methods:{
                onPostLiked(value){
                    this.totalLikes = this.totalLikes + value;
                }
            }
        });

Notice that we have made a couple of changes in our Post component.

We now have added a custom event on like component @postLiked="onPostLiked", This means that whenever like component emits postLiked event, the post component is listening to it and wants to call its own method named onPostLiked.
Inside onPostLiked method, we simple increment/decrement the totalLiked depending upon the value passed.

Here is how the final output look

[WP-Coder id="13"]

Comments