Simple comment section with vue components
Tags: frontend, vue, components, javascript
Published: 2018-04-25 10:27:06

---
title: Simple comment section with vue components
published: true
description: Simple comment section with vue components
tags: frontend,vue, components, javascript
cover_image: https://thepracticaldev.s3.amazonaws.com/i/5i9qtks63sbr380v1bct.png
---
Recently I started to migrate the frontend part of my work from jquery to Vue.js and it feels amazing! I always liked working on the frontend, but working with Vue just feels right.

Since we try to migrate slowly we currently use the UMD build of vue and we just import it with a script tag. This allows us to make use of the majority of the features that the framework offers.

One of the last things I had to built was a small comment section, that will be used under some posts.
###Sneak peek
![alt text](https://thepracticaldev.s3.amazonaws.com/i/x87l1eqvltc6l40soqr9.gif 
 "Small comment section with Vue")

When working with components I like to create a separate file for the **app** and a new file for each new **component**. This is a personal preference, others use different file structures.

###Show me the code 🤖
```html
<div class="comments-outside">
    <div class="comments-header">
        <div class="comments-stats">
            <span><i class="fa fa-thumbs-up"></i> [[ likes ]]</span>
            <span><i class="fa fa-comment"></i> [[ comments.length ]]</span>
        </div>
        <div class="project-owner">
            <div class="avatar">
                <img :src="creator.avatar" alt="">
            </div>
            <div class="username">
                <a href="#">@[[ creator.user ]]</a>
            </div>
        </div>
    </div>
    <comments 
        :comments_wrapper_classes="['custom-scrollbar', 'comments-wrapper']"
        :comments="comments"
        :current_user="current_user"
        @submit-comment="submitComment"
    ></comments>
</div>
```
The code of the app. 
```javascript
new Vue({
    el: '#app',
    delimiters: ['[[', ']]'],
    data: function() {
        return {
            likes: 12,
            //Info about the owner of the post
            creator: {
                avatar: 'http://via.placeholder.com/100x100/36846e',
                user: 'owner'
            },
            //Some info about the current user
            current_user: {
                avatar: 'http://via.placeholder.com/100x100/a74848',
                user: 'exampler'
            },
            //Comments that are under the post
            comments: [
                {
                    id: uuidv4(),
                    user: 'example',
                    avatar: 'http://via.placeholder.com/100x100/a74848',
                    text: 'lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor',
                },
            ]
        }
    },
    methods: {
        submitComment: function(reply) {
            this.comments.push({
                id: uuidv4(),
                user: this.current_user.user,
                avatar: this.current_user.avatar,
                text: reply
            });
        }
    }
});
```
This will be saved as a separate file named *comments-app.js* and will be included in the html.

So now we have the skeleton of the app and some data to get started, but we still have to make the *comments* component.

Preview:
![alt text](https://thepracticaldev.s3.amazonaws.com/i/3vpu2n5yknorxgan70rj.png 
 "comments component")

```javascript
Vue.component('comments', {
    delimiters: ['[[', ']]'],
    template: `
        <div class="comments">
            <div :class="comments_wrapper_classes">
                <single-comment 
                    v-for="comment in comments"
                    :comment="comment"
                    :key="comment.id"
                ></single-comment>
            </div>
            <hr>
            <div class="reply">
                <div class="avatar">
                    <img :src="current_user.avatar" alt="">
                </div>
                <input 
                    type="text" 
                    v-model.trim="reply" 
                    class="reply--text" 
                    placeholder="Leave a comment..."
                    maxlength="250"
                    required
                    @keyup.enter="submitComment"
                />
                <button 
                    class="reply--button" 
                    @click.prevent="submitComment">
                    <i class="fa fa-paper-plane"></i> Send
                </button>
            </div>
        </div>
    `,
    data: function() {
        return {
            reply: ''
        }
    },
    methods: {
        //Tell the parent component(main app) that we have a new comment
        submitComment: function() {
            if(this.reply != '') {
                this.$emit('submit-comment', this.reply);
                this.reply = '';
            }
        }
    },
    //What the component expects as parameters
    props: ['comments', 'current_user', 'comments_wrapper_classes']
});
```
This will be put into a new file named *comments.js* and we will include it with a script tag in the app.
As you can see we have a new component named *single-comment* that we need to build (I promise this is the last one 😅).
Preview:
![alt text](https://thepracticaldev.s3.amazonaws.com/i/xjubaib7c3s7bpq78ulf.png 
 "Single comment component")
```javascript
Vue.component('single-comment', {
    delimiters: ['[[', ']]'],
    template: `
        <div class="comment">
            <div class="avatar">
                <img :src="comment.avatar" alt="">
            </div>
            <div class="text">
                <a class="username" href="#">
                    @[[ comment.user ]]
                </a> 
                <span>[[ comment.text ]]</span>
            </div>
        </div>
    `,
    props: ['comment']
});
```
This will be put into a new file named *single-comment.js* and we will include it with a script tag in the app.

###Conclusion
Personally whenever I have to create anything I break it down into components and ask myself some questions:
1.Could this be used anywhere else?
2.Does it make sense to be used, as is, somewhere else?
If the answer is yes I create the component.

🎉Thank you for reading through all this and I hope you found something helpful🎉

Let me know if you would like to see the full code, with the css and I will create a github repo.