DEV Community

Cover image for Implement Quick Blog Comments in VueJS
oteri for Hackmamba

Posted on

Implement Quick Blog Comments in VueJS

Blogs share information via written pieces of content. Blog comments can drive engagement or solicit feedback depending on the content domain.

This post teaches how to add a comment section to blog posts. We will be able to add, view, edit, and delete each comment. Also important to note is that we don’t need a custom backend server to implement this feature.

For the complete source code, check out this GitHub repository.

This project is completed and written in Vue.js. Vue is an open-source JavaScript front-end framework for building user interfaces and single-page applications with HTML, CSS, and JavaScript.

View the final product and see the finished look

blog comments

Prerequisites

To complete the tutorial, you need the following:

  • Basic JavaScript knowledge
  • Install Docker Desktop on your local machine. Run this command docker -v to confirm if you have it installed; otherwise, install it through the docker products page
  • Knowledge of Vue.js
  • A locally running Appwrite instance. Follow this documentation to install it.

Appwrite is an open-source backend-as-a-service platform that allows developers to build modern backend APIs faster. Appwrite abstracts the complexities involved with building and managing complex backend services. We don’t require a custom server for this project, and we focus on building the interface.

Getting Started with Vue

We use the Vue CLI terminal command to scaffold a new project having Vue 3, Babel, and ESLint.

vue create blog-comments
Enter fullscreen mode Exit fullscreen mode

After installation, we change the directory and start a local development server on localhost:8080 using:

cd blog-comments && yarn serve

# or

cd blog-comments && npm run serve
Enter fullscreen mode Exit fullscreen mode

Creating a blog page

We import the src/components/Blog.vue component in the App.vue file in the project folder.

components/Blog.vue
https://gist.github.com/Chuloo/68921c6b9729ca2da7ee03fab1dab60c

The code above gives us a page containing a text body, post title, and publisher name, which occurs with the stored blog data as state variables in vue.

We also added scoped styles using the <style> tags for the component.

Next, we import the Blog component to the root component App.vue.

<template>
  <div class="container">
    <Blog />
  </div>
</template>

<script>
import Blog from '@/components/Blog.vue';

export default {
  name: 'App',
  components: {
    Blog,
  }
</script>

<style>
  [component styles go in here]
</style>
Enter fullscreen mode Exit fullscreen mode

Here’s the complete code snippet of the home page.

https://gist.github.com/Chuloo/c6d23d0b7503228b553df180067c2e43

The blog comments page looks like this now:

home page text

Creating the comment input forms

Next, we create input fields with which readers can enter comments.

In the components folder, we create a new file, AddComment.vue, with the following content:

<template>
  <div class="form">
    <form>
      <div class="form__group">
        <label>Leave a comment</label>
        <textarea
          v-model="newComment"
          rows="10"
          required
          cols="50"
          placeholder="type in your comment"
        />
        <button>Submit</button>
      </div>
    </form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      newComment: '',
    };
  },
};
</script>

<style scoped>
.form {
  margin-top: 1.5em;
}

label {
  display: block;
  margin-bottom: 1em;
  font-weight: 700;
  font-family: Padauk, sans-serif;
}

textarea {
  width: 100%;
  margin-top: 0.5em;
}

button {
  border: unset;
  background: #79b791;
  color: #230c0f;
  font-weight: 700;
  padding: 1em 2.5em;
  margin-top: 1em;
}
</style>
Enter fullscreen mode Exit fullscreen mode

The code above has a data property newComment set to an empty string. This property is bound to the <textarea> field using the v-model directive.

With this in place, let's import the AddComment component into the App.vue component with the following code:

<template>
  <div class="container">
    <Blog />
    <!-- add this -->
    <add-comment />
  </div>
</template>

<script>
// other import component
import AddComment from '@/components/AddComment.vue'; // add this
export default {
  name: 'App',
  components: {
    // blog component
    AddComment // add this
  }
</script>
<style>
/* styles for the page */
</style>
Enter fullscreen mode Exit fullscreen mode

The result of the blog should look like this:

text input area blog

Next, we will list all comments created under a post. We will also include options to update or delete a comment.

We create a file, Comment.vue, in the components folder with the following content:

<template>
  <div class="comment">
    <div class="comment__flex">
      <p>I found this article helpful</p>
      <div class="comment__flex-btn">
        <button class="update">Update</button>
        <button class="del">Delete</button>
      </div>
    </div>
  </div>
</template>

<style>
[Styles go in here]
</style>
Enter fullscreen mode Exit fullscreen mode

You can see the complete component with styles in this gist.

https://gist.github.com/Chuloo/0edc8d42d8c69221b6cac39eafa93204

Finally, let's include the Comment component in the App.vue file.

<template>
  <div class="container">
    <Blog />
    <!-- add this -->
    <div class="comment-space">
      <p>Comment (1)</p>
    </div>
    <div>
      <comment class="message" />
    </div>
    <add-comment />
  </div>
</template>

<script>
// other import component
import Comment from '@/components/Comment';

export default {
  name: 'App',
  components: {
    // other components
    Comment, // add this
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

All the data on the page is static, and the page looks like the image below.

blog

Next, we’ll add interactivity to the page.

Appwrite project setup

To use Appwrite in this Vue application, we install the Appwrite client-side SDK with the command.

yarn add appwrite

# or

npm install appwrite
Enter fullscreen mode Exit fullscreen mode

Next, let's set up the app by creating a new Appwrite project.

Create a new Appwrite Project

We click the Create Project button to start a new project on our Appwrite web console (either local or hosted).

After that, we obtain the Project ID and API Endpoint in the project's settings tab.

In the project’s root directory, we create a utils.js file to define a new Appwrite instance and other helpful application variables.

import { Appwrite } from 'appwrite';
// Init your Web SDK
const appwrite = new Appwrite();
appwrite
  .setEndpoint('http://EndpointURL.example') // Replace this with your endpoint
  .setProject('ProjectID'); // Replace this with your ProjectID

appwrite.account.createAnonymousSession().then(
  (response) => {
    console.log(response);
  },
  (error) => {
    console.log(error);
  }
);

export const db = appwrite.database;
export const COLLECTION_ID = 'COLLECTION ID'; // Replace with your Collection ID
Enter fullscreen mode Exit fullscreen mode

To bypass some security requirements, we created an anonymous session on Appwrite.

Creating the database collection

Appwrite provides a functional database with which we will store our blog comments.

To create a collection in our Appwrite console panel, we navigate to the Database tab, click the Add Collection button, and provide a collection name. We copy the CollectionID as we require it to interact with the collection using the client-side SDK.

At the Collection Level within the settings tab, we set the Read and Write access to have the value of role:all.

blog

Update the data in utils.js to include the Appwrite credentials obtained.

Finally, in the attributes tab, let's create the properties for our documents. For this application, we store the comment and date of each comment.

blog comment

Fetch all comments

We require a function to fetch all comments when the app loads. We do this in the script portion of App.vue with:

<script>
import { COLLECTION_ID, db } from '@/utils';

export default {
  name: 'App',
  components: {
    // all components
  },
  created() {
    this.fetchComments();
  },
  data() {
    return {
      comments: [],
    };
  },
  methods: {
    fetchComments() {
      let promise = db.listDocuments(COLLECTION_ID);
      promise.then(
        (res) => {
          console.log(res);
          this.comments = res.documents;
        },
        (err) => {
          console.log(err);
        }
      );
    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

We created the comments array in the data() function to store comments we retrieve using the listDocuments API.

In the created() lifecycle method, run the fetchComments() function when the App component is created.

We update the HTML in the <template> section of the App.vue component with the following.

<template>
  <div class="container">
    <Blog />
    <div class="comment-space">
      <p>
        {{
          comments.length > 1
            ? `Comments (${comments.length})`
            : comments.length == 1
            ? `Comment (${comments.length})`
            : ''
        }}
      </p>
    </div>
    <div v-for="data in comments" :key="data.comment">
      <!-- comment component goes here -->
    </div>
    <add-comment :fetchComments="fetchComments" />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

The <p> tag contains a ternary operator that shows the number of comments. Using the v-for directive, we loop through and render each comment.

To reuse the function to fetch all comments after creating a new comment, we bind the :fetchComments prop to the fetchComments method we defined earlier.

Creating a blog comment

We move to the AddComment.vue file to handle a comment’s addition to the database.

<template>
  <div class="form">
    <form @submit.prevent="createNewComment">
      <div class="form__group">
        <label>Leave a comment</label>
        <textarea
          v-model="newComment"
          rows="10"
          required
          cols="50"
          placeholder="type in your comment"
        />
        <button>Submit</button>
      </div>
    </form>
  </div>
</template>

<script>
import { COLLECTION_ID, db } from '@/utils';

export default {
  props: ['fetchComments'],
  // data ()
  methods: {
    createNewComment() {
      if (this.newComment === '') {
        return;
      }
      let promise = db.createDocument(COLLECTION_ID, 'unique()', {
        comment: this.newComment,
        date: new Date(),
      });
      promise.then(
        () => {
          this.fetchComments();
          this.newComment = '';
        },
        (err) => {
          console.log(err);
        }
      );
    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

In the createNewComment method, we use Appwrite’s createDocument API to write a new comment to the database. An error message is logged if the write operation fails. We fetch an updated list of all comments after adding a new comment.

The Appwrite web console will display one document representing a comment in the image below:

blog

Updating the Comment list Component

In the App.vue component, we update the comment component’s props to include the comment data and the fetchComments method.

<template>
  <div class="container">
    <-!-- Blog component --> <-!-- Comment count -->
    <div v-for="data in comments" :key="data.comment">
      <-!-- add this -->
      <comment class="message" :data="data" v-on:refreshData="fetchComments" />
    </div>
    <-!-- add-comment component -->
  </div>
</template>

<script>
// import component
import Comment from '@/components/Comment';

export default {
  components: {
    // other components
    Comment,
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

fetchComments runs once the refreshData event is fired.

Let's update the Comment.vue component to handle comment updates and deletion. We will also include a component to edit a comment. First, we add the update comment function in the script portion with:

<script>
import { db } from '@/utils';
export default {
  props: ['data'],
  data() {
    return {
      open: false,
      displayedComment: '',
    };
  },
  methods: {
    updateComment() {
      this.open = !this.open;
    },
    updateCommentMethod() {
      let promise = db.updateDocument(this.data.$collection, this.data.$id, {
        comment: this.displayedComment,
      });
      this.open = false;
      promise.then(
        () => {
          this.$emit('refreshData');
        },
        (err) => {
          console.log(err);
        }
      );
    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

We added a state variable to manage the visibility of a comment’s action buttons and another variable to hold the new text. Appwrite’s updateDocument API uses the collection ID and document ID passed as props to update the comment. Once the comment is updated, we emit the refreshData event to fetch all comments.

We update the template portion to utilize the methods and variables created.

<template>
  <div class="comment">
    <div class="comment__flex">
      <p>{{ data.comment }}</p>
      <div class="comment__flex-btn">
        <button class="update" @click="updateComment">Update</button>
        <button class="del" @click="deleteComment">Delete</button>
      </div>
    </div>
    <div v-if="this.open" class="open">
      <form @submit.prevent="updateCommentMethod">
        <div class="form-group">
          <textarea
            cols="50"
            rows="10"
            id
            required
            :placeholder="data.comment"
            v-model="displayedComment"
          />
          <button class="update">Update</button>
        </div>
      </form>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Lastly, we add a method to delete a comment using Appwrite’s deleteDocument API.

<script>
export default {
  methods: {
    deleteComment() {
      let promise = db.deleteDocument(this.data.$collection, this.data.$id);
      promise.then(
        () => {
          this.$emit('refreshData');
        },
        (err) => {
          console.log('error occured', err);
        }
      );
    },
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

The image below is the final look of the web page.

blog

Conclusion

This post is an in-depth guide on using Appwrite to create, display, edit, and delete blog comments. As seen, this feature doesn’t require a custom backend server. Try to add more blog posts and create unique comments for each.

Learn More

Top comments (3)

Collapse
 
moose_said profile image
Mostafa Said

Super helpful, thank you!

Collapse
 
terieyenike profile image
oteri

Glad my article was helpful.

Collapse
 
chloe999 profile image
chloe decker

Thank you so much for this awesome article fix connections to wireless displays in windows 10 click and get the simple process and fix it.

Some comments have been hidden by the post's author - find out more