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, Laravel 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 so, please download from my github account we are also add link here Download working


  • 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 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 .




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 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 .




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 .




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}', 'CommentController@index');
// Route for store comment
Route::post('comments', 'CommentController@store');
// Route for update comment
Route::post('comments/{commentId}/{type}', 'CommentController@update');



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 .




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



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 .


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 in it so, open Comments.vue file and put into following templet




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

            <form  name="form">
                <div >
                    <pre  placeholder="Add comment..." required v-model="message"></pre>
                    <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">
                        <pre  placeholder="Add comment..." required></pre>
                    </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 >
                            <pre  placeholder="Add comment..." required v-model="message"></pre>
                            <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 >
                                        <pre  placeholder="Add comment..." required v-model="message"></pre>
                                        <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 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 so, please download from my github account we are also add link here Download working


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 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 Keep reading our blogs

For More Info See :: laravel And github

Leave a Comment

Your email address will not be published. Required fields are marked *

40  +    =  49

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