Real Time Comment System With Laravel And Vuejs

Real Time Comment System With Laravel And Vuejs

In this post we will give you information about Real Time Comment System With Laravel And Vuejs. Hear we will give you detail about Real Time Comment System With Laravel And VuejsAnd how to use it also give you demo for it if it is necessary.

Today, Laravelcode share sommething new and very usefull tutorials with every one. Realtime comment system built using laravel and vuejs. comment system required every website. so, we are created here comment system with some awesome functionality. when user comment and post it then instently comment show in the page.

In this tutorials we are create one sapareted comment module and in this comment module we are cover following functionality. after user register then they will be able to do all functionality or action.

NOTE : In this tutorials we are not adding some file like css, we are cover some basiv stuff in this tutorials. if you get woring code so, please download from my github account we are also add link here Download working code

  • Add new comments
  • Reply to comments
  • Up and Down votes
  • Mark spam comments

In this our tutorials for make comment system we are using following technologies :

  • Bootstrap
  • Loadash
  • Vue-resource
  • Laravel Mix

Now we are starting our comment system tutorials step by step.

Step : 1 Create comments table migration

First, we need to create comment table for stare all comment data and aslo span and comment voting data. so, create new one migration by following command.


php artisan make:migration comments

Now copy following migration code and past in your migration file.


Schema::create('comments', function (Blueprint $table) {
    $table->increments('id');
    $table->text('comment');
    $table->integer('votes')->default(0);
    $table->integer('spam')->default(0);
    $table->integer('reply_id')->default(0);
    $table->string('page_id')->default(0);
    $table->integer('users_id');
    $table->timestamps();
});

Schema::create('comment_user_vote', function (Blueprint $table) {
    $table->integer('comment_id');
    $table->integer('user_id');
    $table->string('vote',11);
});

Schema::create('comment_spam', function (Blueprint $table) {
    $table->integer('comment_id');
    $table->integer('user_id');
});

Now run your migration file using following command


php artisan migrate

Step : 2 Create Auth for Comment System

Now, we are created laravel built-in auth system using following command


php artisan make:auth

Step : 3 Create Models for the Comment System

Now, we are created model for comments table by run followign command


php artisan make:model Comment

Then open your app/Comment.php file and put into it following code.


namespace App;

use IlluminateDatabaseEloquentModel;

class Comment extends Model
{
   	protected $fillable = ['comment','votes','spam','reply_id','page_id','users_id'];
 
   	protected $dates = ['created_at', 'updated_at'];
 
  	public function replies()
   	{
       return $this->hasMany('AppComment','id','reply_id');
   	}
}

In above code we are define required fillable columns fields with $fillable and create one replies() method which has the one-many relationship with own.

Now create a model for comment_user_vote. Run the following command:


php artisan make:model CommentVote

Now open your app/CommentVote.php file and put into following code.


namespace App;

use IlluminateDatabaseEloquentModel;

class CommentVote extends Model
{
    protected $fillable = ['comment_id','user_id','vote'];
 
   	protected $table = "comment_user_vote";
 
   	public $timestamps = false;
}

Now, create last one model for comment_spam table


php artisan make:model CommentSpam

Now open your app/CommentSpam.php file and put into following code.


namespace App;

use IlluminateDatabaseEloquentModel;

class CommentSpam extends Model
{
	protected $fillable = ['comment_id','user_id'];

	protected $table = "comment_spam";
 
	public $timestamps = false;
}

Step : 4 Create the Routes for Comments

Now, we are creating following route for required in out comment system. open your routes/web.php and past following route in it.


Route::get('/{pageId}', function($pageId) {
	return view('page',['pageId' => $pageId]);
});
// Route for index page
Route::get('comments/{pageId}', '[email protected]');
// Route for store comment
Route::post('comments', '[email protected]');
// Route for update comment
Route::post('comments/{commentId}/{type}', '[email protected]');

Step : 5 Create the Controller for Comment

Now, create controller for comment by run following command :


php artisan make:controller CommentController

After run this command then your controller file automatic generated in app/Http/Controllers/CommentController.php open it and place in it following code.


namespace AppHttpControllers;

use IlluminateHttpRequest;
use AppComment;
use AppCommentVote;
use AppCommentSpam;

class CommentController extends Controller
{
	public function index($pageId)
	{
    	//
		$comments = Comment::where('page_id',$pageId)->get();
		$commentsData = [];
		foreach ($comments as $key) {
			$user = User::find($key->users_id);
			$name = $user->name;
			$replies = $this->replies($key->id);
			$photo = $user->first()->photo_url;
			// dd($photo->photo_url);
			$reply = 0;
			$vote = 0;
			$voteStatus = 0;
			$spam = 0;

			if(Auth::user()) {
				$voteByUser = CommentVote::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();
				$spamComment = CommentSpam::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();
				if($voteByUser) {
					$vote = 1;
					$voteStatus = $voteByUser->vote;
				}
		    	if($spamComment) {
		           	$spam = 1;
		       	}
		   	}
		   	if(sizeof($replies) > 0) {
		       	$reply = 1;
		   	}
		   	if(!$spam) {
		       	array_push($commentsData,[
		           	"name" => $name,
		           	"photo_url" => (string)$photo,
		           	"commentid" => $key->id,
		           	"comment" => $key->comment,
		           	"votes" => $key->votes,
		           	"reply" => $reply,
		           	"votedByUser" =>$vote,
		           	"vote" =>$voteStatus,
		           	"spam" => $spam,
		           	"replies" => $replies,
		           	"date" => $key->created_at->toDateTimeString()
		       	]);
		   	}
	   	}
	   	$collection = collect($commentsData);
	   	return $collection->sortBy('votes');
   	}
 
	protected function replies($commentId)
   	{
       	$comments = Comment::where('reply_id',$commentId)->get();
       	$replies = [];
       	foreach ($comments as $key) {
           	$user = User::find($key->users_id);
           	$name = $user->name;
           	$photo = $user->first()->photo_url;
           	$vote = 0;
           	$voteStatus = 0;
           	$spam = 0;        
 
           	if(Auth::user()) {
               	$voteByUser = CommentVote::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();
               	$spamComment = CommentSpam::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();
               	if($voteByUser) {
                   	$vote = 1;
                   	$voteStatus = $voteByUser->vote;
               	}
               	if($spamComment) {
                   $spam = 1;
               	}
           	}
 
           	if(!$spam) {
               	array_push($replies,[
                   	"name" => $name,
                   	"photo_url" => $photo,
                   	"commentid" => $key->id,
                   	"comment" => $key->comment,
                   	"votes" => $key->votes,
                   	"votedByUser" => $vote,
                   	"vote" => $voteStatus,
                   	"spam" => $spam,
                   	"date" => $key->created_at->toDateTimeString()
               	]);
       		}
       	$collection = collect($replies);
       	return $collection->sortBy('votes');
   	}

	public function store(Request $request)
   	{
       	$this->validate($request, [
       		'comment' => 'required',
       		'reply_id' => 'filled',
       		'page_id' => 'filled',
       		'users_id' => 'required',
       	]);
 
       	$comment = Comment::create($request->all());
 
       	if($comment)
           return [ "status" => "true","commentId" => $comment->id ];
   	}

	public function update(Request $request, $commentId, $type)
   	{
       	if($type == "vote"){
           	$this->validate($request, [
           		'vote' => 'required',
           		'users_id' => 'required',
           	]);
 
           	$comments = Comment::find($commentId);
 
           	$data = [
               	"comment_id" => $commentId,
               	'vote' => $request->vote,
               	'user_id' => $request->users_id,
           	];
 
           	if($request->vote == "up"){
               	$comment = $comments->first();
               	$vote = $comment->votes;
               	$vote++;
               	$comments->votes = $vote;
               	$comments->save();
           	}
 
           	if($request->vote == "down"){
               	$comment = $comments->first();
               	$vote = $comment->votes;
               	$vote--;
               	$comments->votes = $vote;
               	$comments->save();
           	}
 
           	if(CommentVote::create($data))
               return "true";
       	}
 
       	if($type == "spam") {
           	$this->validate($request, [
               	'users_id' => 'required',
           	]);
 
           	$comments = Comment::find($commentId);
           	$comment = $comments->first();
           	$spam = $comment->spam;
           	$spam++;
           	$comments->spam = $spam;
           	$comments->save();
 
           	$data = [
               	"comment_id" => $commentId,
               	'user_id' => $request->users_id,
      		];
 
           	if(CommentSpam::create($data))
               	return "true";
       	}
   	}
}

Step : 6 Comment Component Using VueJS

[ADDCODE]

Run following command for install all package.json file dependencies.


npm install

Now, we are required vue-resource so, run following command for it


npm install --save vue-resource

Now, go to the this path resources/assets/js/components and create one blank file Comments.vue. now leave it blank. and open your resources/assets/js/app.js and add following code.

Add the following line after require(‘./bootstrap’);


import VueResource from "vue-resource"

Now, Add the following line after window.Vue = require(‘vue’);


Vue.use(VueResource);
Vue.component('comment', require('./components/Comments.vue'));

Step : 6 Write Code For Comments.vue

We are already create Comments.vue file before but then we are not put any code in it so, open Comments.vue file and put into following templet code


<template>
    <div >
        <h1>Comments</h1>
        <!-- From -->
        <div  v-if="user">
            <!-- Comment Avatar -->
            <div >
                <img src="storage/commentbox.png">
            </div>

            <form  name="form">
                <div >
                    <textarea  placeholder="Add comment..." required v-model="message"></textarea>
                    <span  v-if="errorComment" style="color:red">{{errorComment}}</span>
                </div>
                <div >
                    <input  placeholder="Email" type="text" disabled :value="user.name">
                </div>
                <div >
                    <input type="button"  @click="saveComment" value="Add Comment">
                </div>
            </form>
        </div>

        <div  v-else>
            <!-- Comment Avatar -->
            <div >
                <img src="storage/commentbox.png">
            </div>

            <form  name="form">
                <div >
                    <a href="login">
                        <textarea  placeholder="Add comment..." required></textarea>
                    </a>
                </div>
            </form>
        </div>
        <!-- Comments List -->
        <div  v-if="comments" v-for="(comment,index) in commentsData">
            <!-- Comment -->
            <div v-if="!spamComments[index] || !comment.spam" >
                <!-- Comment Avatar -->
                <div >
                    <img src="storage/comment.png">
                </div>
                <!-- Comment Box -->
                <div >
                    <div >{{comment.comment}}</div>
                    <div >
                        <div >
                            <span >
                               <em>{{ comment.name}}</em>
                            </span>
                            <span >{{ comment.date}}</span>
                        </div>
                        <div >
                            <ul >
                                <li>Votes: {{comment.votes}}
                                    <a v-if="!comment.votedByUser" v-on:click="voteComment(comment.commentid,'directcomment',index,0,'up')">Up Votes</a>
                                    <a v-if="!comment.votedByUser" v-on:click="voteComment(comment.commentid,'directcomment',index,0,'down')">Down Votes</a>
                                </li>
                                <li>
                                    <a v-on:click="spamComment(comment.commentId,'directcomment',index,0)">Spam</a>
                                </li>
                                <li>
                                    <a v-on:click="openComment(index)">Reply</a>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>=
                <!-- From -->
                <div  v-if="commentBoxs[index]">
                    <!-- Comment Avatar -->
                    <div >
                        <img src="storage/comment.png">
                    </div>
                    <form  name="form">
                        <div >
                            <textarea  placeholder="Add comment..." required v-model="message"></textarea>
                            <span  v-if="errorReply" style="color:red">{{errorReply}}</span>
                        </div>
                        <div >
                            <input  placeholder="Email" type="text" :value="user.name">
                        </div>
                        <div >
                            <input type="button"  v-on:click="replyComment(comment.commentid,index)" value="Add Comment">
                        </div>
                    </form>
                </div>
                <!-- Comment - Reply -->
                <div v-if="comment.replies">
                    <div  v-for="(replies,index2) in comment.replies">
                        <div v-if="!spamCommentsReply[index2] || !replies.spam" >
                            <!-- Comment Avatar -->
                            <div >
                                <img src="storage/comment.png">
                            </div>
                            <!-- Comment Box -->
                            <div  style="background: grey;">
                                <div  style="color: white">{{replies.comment}}</div>
                                <div >
                                    <div >
                                        <span >
                                           {{replies.name}}
                                        </span>
                                        <span >{{replies.date}}</span>
                                    </div>
                                    <div >
                                        <ul >
                                            <li>Total votes: {{replies.votes}}
                                                <a v-if="!replies.votedByUser" v-on:click="voteComment(replies.commentid,'replycomment',index,index2,'up')">Up Votes</a>
                                                <a v-if="!replies.votedByUser" v-on:click="voteComment(comment.commentid,'replycomment',index,index2,'down')">Down Votes</a>
                                                </a>
                                            </li>
                                            <li>
                                                <a v-on:click="spamComment(replies.commentid,'replycomment',index,index2)">Spam</a>
                                            </li>
                                            <li>
                                                <a v-on:click="replyCommentBox(index2)">Reply</a>
                                            </li>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                            <!-- From -->
                            <div  v-if="replyCommentBoxs[index2]">
                                <!-- Comment Avatar -->
                                <div >
                                    <img src="storage/comment.png">
                                </div>
                                <form  name="form">
                                    <div >
                                        <textarea  placeholder="Add comment..." required v-model="message"></textarea>
                                        <span  v-if="errorReply" style="color:red">{{errorReply}}</span>
                                    </div>
                                    <div >
                                        <input  placeholder="Email" type="text" :value="user.name">
                                    </div>
                                    <div >
                                        <input type="button"  v-on:click="replyComment(comment.commentid,index)" value="Add Comment">
                                    </div>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

Step : 6 Add Script For Comments.vue

Now add following script code in Comments.vue file after closing template tag.


<script>
    var _ = require('lodash');
    export default {
        props: ['commentUrl'],
        data() {
            return {
                comments: [],
                commentreplies: [],
                comments: 0,
                commentBoxs: [],
                message: null,
                replyCommentBoxs: [],
                commentsData: [],
                viewcomment: [],
                show: [],
                spamCommentsReply: [],
                spamComments: [],
                errorComment: null,
                errorReply: null,
                user: window.user
            }
        },

        http: {
            headers: {
                'X-CSRF-TOKEN': window.csrf
            }
        },

        methods: {
            fetchComments() {
                this.$http.get('comments/' + this.commentUrl).then(res => {
                    this.commentData = res.data;
                    this.commentsData = _.orderBy(res.data, ['votes'], ['desc']);
                    this.comments = 1;
                });
            },
            showComments(index) {
                if (!this.viewcomment[index]) {
                    Vue.set(this.show, index, "hide");
                    Vue.set(this.viewcomment, index, 1);
                } else {
                    Vue.set(this.show, index, "view");
                    Vue.set(this.viewcomment, index, 0);
                }
            },
            openComment(index) {
                if (this.user) {
                    if (this.commentBoxs[index]) {
                        Vue.set(this.commentBoxs, index, 0);
                    } else {
                        Vue.set(this.commentBoxs, index, 1);
                    }
                }
            },
            replyCommentBox(index) {
                if (this.user) {
                    if (this.replyCommentBoxs[index]) {
                        Vue.set(this.replyCommentBoxs, index, 0);
                    } else {
                        Vue.set(this.replyCommentBoxs, index, 1);
                    }
                }
            },
            saveComment() {
                if (this.message != null && this.message != ' ') {
                    this.errorComment = null;
                    this.$http.post('comments', {
                        page_id: this.commentUrl,
                        comment: this.message,
                        users_id: this.user.id
                    }).then(res => {
                        if (res.data.status) {
                            this.commentsData.push({
                                "commentid": res.data.commentId,
                                "name": this.user.name,
                                "comment": this.message,
                                "votes": 0,
                                "reply": 0,
                                "replies": []
                            });
                            this.message = null;
                        }
                    });
                } else {
                    this.errorComment = "Please enter a comment to save";
                }
            },
            replyComment(commentId, index) {
                if (this.message != null && this.message != ' ') {
                    this.errorReply = null;
                    this.$http.post('comments', {
                        comment: this.message,
                        users_id: this.user.id,
                        reply_id: commentId
                    }).then(res => {
                        if (res.data.status) {
                            if (!this.commentsData[index].reply) {
                                this.commentsData[index].replies.push({
                                    "commentid": res.data.commentId,
                                    "name": this.user.name,
                                    "comment": this.message,
                                    "votes": 0
                                });
                                this.commentsData[index].reply = 1;
                                Vue.set(this.replyCommentBoxs, index, 0);
                                Vue.set(this.commentBoxs, index, 0);
                            } else {
                                this.commentsData[index].replies.push({
                                    "commentid": res.data.commentId,
                                    "name": this.user.name,
                                    "comment": this.message,
                                    "votes": 0
                                });
                                Vue.set(this.replyCommentBoxs, index, 0);
                                Vue.set(this.commentBoxs, index, 0);
                            }
                            this.message = null;
                        }
                    });
                } else {
                    this.errorReply = "Please enter a comment to save";
                }
            },
            voteComment(commentId, commentType, index, index2, voteType) {
                if (this.user) {
                    this.$http.post('comments/' + commentId + '/vote', {
                        users_id: this.user.id,
                        vote: voteType
                    }).then(res => {
                        if (res.data) {
                            if (commentType == 'directcomment') {
                                if (voteType == 'up') {
                                    this.commentsData[index].votes++;
                                } else if (voteType == 'down') {
                                    this.commentsData[index].votes--;
                                }
                            } else if (commentType == 'replycomment') {
                                if (voteType == 'up') {
                                    this.commentsData[index].replies[index2].votes++;
                                } else if (voteType == 'down') {
                                    this.commentsData[index].replies[index2].votes--;
                                }
                            }
                        }
                    });
                }
            },
            spamComment(commentId, commentType, index, index2) {
                console.log("spam here");
                if (this.user) {
                    this.$http.post('comments/' + commentId + '/spam', {
                        users_id: this.user.id,
                    }).then(res => {
                        if (commentType == 'directcomment') {
                            Vue.set(this.spamComments, index, 1);
                            Vue.set(this.viewcomment, index, 1);
                        } else if (commentType == 'replycomment') {
                            Vue.set(this.spamCommentsReply, index2, 1);
                        }
                    });
                }
            },
        },

        mounted() {
            console.log("mounted");
            this.fetchComments();
        }
    }
</script>

NOTE : In this tutorials we are not adding some file like css, we are cover some basiv stuff in this tutorials. if you get woring code so, please download from my github account we are also add link here Download working code

Now we are ready to run our example so run bellow command ro quick run:

php artisan serve

Now you can open bellow URL on your browser:

http://localhost:8000

If you face any problem then please write a comment or give some suggestions for improvement. Thanks…

Hope this code and post will helped you for implement Real Time Comment System With Laravel And Vuejs. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs

For More Info See :: laravel And github

We're accepting well-written guest posts and this is a great opportunity to collaborate : Contact US