I'm learning Vuejs (not too proficient in Laravel in the first place), and I'm trying to make a simple voting system on some tasks. I managed to do adding tasks, editing them, and deleting them, but when I added the upvote/downvote stuff, the number of votes doesn't change.
So here are the Laravel routes in the routes\api.php
:
Route::group(['middleware'=>'api'],function(){
Route::get('tasks', function(){
return \App\Task::latest()->orderBy('created_at', 'desc')->get();
});
Route::get('task/{id}', function($id){
return \App\Task::findOrFail($id);
});
Route::post('task/store', function(Request $request){
return App\Task::create(['body' => $request->input(['body'])]);
});
Route::patch('task/{id}', function(Request $request, $id){
return \App\Task::findOrFail($id)->update(['body' => $request->input(['body'])]);
});
Route::delete('task/{id}', function($id){
return \App\Task::destroy($id);
});
Route::get('task/{id}/votes', function($id){
return \App\Task::findOrFail($id)->votes->get();
});
Route::patch('task/{id}/votes', function(Request $request, $id){
return \App\Task::findOrFail($id)->update(['votes'=> $request->input(['votes'])]);
});
});
The migration for the Tasks table looks like this (I used sqlite):
Schema::create('tasks', function (Blueprint $table) {
$table->increments('id');
$table->text('body');
$table->integer('votes')->default(1);
$table->timestamps();
});
This is the Tasks component template for Vue:
<h1>My Tasks</h1>
<hr>
<h4>New Task</h4>
<form action="#" @submit.prevent="edit ? updateTask(task.id) : createTask()">
<div class="input-group">
<input type="text" name="body" v-model="task.body" v-el:taskinput class="form-control" autofocus>
<span class="input-group-btn">
<button type="submit" class="btn btn-success" v-show="!edit">New Task</button>
<button type="submit" class="btn btn-primary" v-show="edit">Edit Task</button>
</span>
</div>
</form>
<hr>
<hr>
<h3>All Tasks</h3>
<ul class="list-group">
<li class="list-group-item" v-for="task in list">
{{ task.body }}
<button class="btn-success btn-xs" @click="upvote(task.id)" :class="{disabled: upvoted}">Upvote</button>
<span class="label label-primary">{{ task.votes }}</span>
<button class="btn-danger btn-xs" @click="downvote(task.id)" :class="{disabled: downvoted}">Downvote</button>
<span class="pull-right">
<button class="btn-primary btn-xs" @click="showTask(task.id)">Edit Task</button>
<button class="btn-danger btn-xs" @click="deleteTask(task.id)">Delete Task</button>
</span>
</li>
</ul>
And finally, the Vue script:
export default{
data(){
return{
edit: false,
list: [],
task: {
id: '',
body: '',
votes: Number
},
upvoted: false,
downvoted: false
}
},
ready: function () {
this.fetchTaskList();
},
methods:{
fetchTaskList: function () {
this.$http.get('api/tasks').then(function (response) {
this.list = response.data
});
},
createTask: function () {
this.$http.post('api/task/store', this.task);
this.task.body = '';
this.edit = false;
this.fetchTaskList();
},
updateTask: function (id) {
this.$http.patch('api/task/' + id, this.task);
this.task.body='';
this.edit = false;
this.fetchTaskList();
},
showTask: function (id) {
this.$http.get('api/task/' + id).then(function (response) {
this.task.id = response.data.id;
this.task.body = response.data.body;
});
this.$els.taskinput.focus();
this.edit = true;
},
deleteTask: function (id) {
this.$http.delete('api/task/' + id);
this.fetchTaskList();
},
updateVotes: function (id, votes) {
this.$http.patch('api/task/'+id+'/votes', votes);
},
upvote: function (id) {
this.$http.get('api/task/'+id+'/votes').then(function (response) {
this.task.id = response.data.id;
this.task.votes = response.data.votes + 1;
updateVotes(this.task.id, this.task.votes);
});
this.upvoted = !this.upvoted;
this.downvoted = false;
},
downvote: function (id) {
this.$http.get('api/task/'+id+'/votes').then(function (response) {
this.task.id = response.data.id;
this.task.votes = response.data.votes - 1;
updateVotes(this.task.id, this.task.votes);
});
this.upvoted = false;
this.downvoted = !this.downvoted;
},
}
}
I'm guessing the error is somewhere in the Vue script, either I'm declaring votes wrong (votes: Number ?), or I can't call updateVotes function from the upvote and downvote functions like I did.
Edit: Still not working, but I have Vue.js devtools and it's definitely recognizing the votes: https://snag.gy/sE5gp6.jpg
...but in a very weird way. When I click upvote, the votes in the devtools changes to '11', not 1. When I click downvote, it goes back to 0. It doesn't change in the view, though. This is all after I've made the change from:
updateVotes(this.task.id, this.task.votes);
To:
this.updateVotes(this.task.id, this.task.votes);
..as the user Dan suggested, and after changing the:
upvote: function (id) {
this.$http.get('api/task/'+id+'/votes')
To:
upvote: function (id) {
this.$http.get('api/task/'+id)
as I think I was previously getting just the votes and then treating them like a Task object for the rest of the function. Same for the downvote function.
This is what comes up in console now:
vue-resource.common.js?d39b:966 PATCH http://localhost:8000/api/task/8/votes 500 (Internal Server Error)(anonymous function) @ vue-resource.common.js?d39b:966Promise$1 @ vue-resource.common.js?d39b:192xhrClient @ vue-resource.common.js?d39b:927sendRequest @ vue-resource.common.js?d39b:1060exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042before @ vue-resource.common.js?d39b:881exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042timeout @ vue-resource.common.js?d39b:920exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042method @ vue-resource.common.js?d39b:895exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042body @ vue-resource.common.js?d39b:802exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042jsonp @ vue-resource.common.js?d39b:867exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042header @ vue-resource.common.js?d39b:903exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042cors @ vue-resource.common.js?d39b:777exec @ vue-resource.common.js?d39b:1017next @ vue-resource.common.js?d39b:1042(anonymous function) @ VM56:32exec @ vue-resource.common.js?d39b:1017(anonymous function) @ vue-resource.common.js?d39b:1045Promise$1 @ vue-resource.common.js?d39b:192Client @ vue-resource.common.js?d39b:1010Http @ vue-resource.common.js?d39b:1152Http.(anonymous function) @ vue-resource.common.js?d39b:1188updateVotes @ Tasks.vue?34c5:94(anonymous function) @ vue.common.js?4a36:216(anonymous function) @ Tasks.vue?34c5:102 localhost/:1 Uncaught (in promise) Response {url: "api/task/8/votes", body: "↵↵ ↵ ↵↵↵ ↵ ↵", headers: Object, status: 500, statusText: "Internal Server Error"…}
Does it work if you replace:
updateVotes(this.task.id, this.task.votes);
With
this.updateVotes(this.task.id, this.task.votes);
(Posted on behalf of the OP).
The problem is solved. I didn't add protected $fillable = ['votes']
in the Task model.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With