Implement quick blog comments in VueJS

This page summarizes the projects mentioned and recommended in the original post on dev.to

Our great sponsors
  • Appwrite - The Open Source Firebase alternative introduces iOS support
  • SonarQube - Static code analysis for 29 languages.
  • Scout APM - Less time debugging, more time building
  • appwrite-blog-comments-with-vue

    Quick blog comments in Vue.js and using Appwrite for storing data

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

  • Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    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.

  • Appwrite

    Appwrite - The Open Source Firebase alternative introduces iOS support . Appwrite is an open source backend server that helps you build native iOS applications much faster with realtime APIs for authentication, databases, files storage, cloud functions and much more!

  • Appwrite

    Secure Backend Server for Web, Mobile & Flutter Developers 🚀 AKA the 100% open-source Firebase alternative.

    We also added scoped styles using the 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 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-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 />
            
            <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 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">
              
            </div>
            <add-comment :fetchComments="fetchComments" />
          </div>
        </template>
    
    Enter fullscreen mode Exit fullscreen mode

    The

    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

NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts