Reputation: 465
I'm trying to get a good understanding of VueJS, and I'm using it with Laravel 5.7 for a personal project, but I can't exactly figure out how to do a, probably, simple task a "like" button\icon.
So, here's the situation, I have a page, displaying various posts from my database, and at the bottom of each post I want a "like toogle" button, which I made with an icon followed by the number of likes on that post; At first the button will contain the data retrieved from the corresponding database table, but if you click it will increase the displayed number by one and insert a new like in the database.
I made the "like" icon as a component :
<section class="bottomInfo">
<p>
<likes now="{{ $article->likes }}"></likes>
<span class="spacer"></span>
<span class="entypo-chat">
{{ $article->comments }}
</p>
</section> <!-- end .bottomInfo -->
As you can see there's a <likes>
in which I added a prop now
, by what I'm understanding till now about components, in this way I can insert the data from my db as a starting value (now
contains the db row value), problem is, I don't know where\how to keep that value in my app, in which I'm gonna also use axios for increasing the likes.
Here's the component:
<template>
<span class="entypo-heart"> {{ now }}</span>
</template>
<script>
export default {
props: ['now'],
data() {
return {
like: this.now
}
},
mounted() {
console.log('Component mounted.');
}
}
</script>
What I tried to do (and I don't know if it's correct) is to pass the value of now
to the data
function inside a property named like
, so, if I understood correctly, that variable like
is now part of my properties in my main Vue instance, which is this one
const app = new Vue({
el: '#main',
mounted () {
console.log("The value of 'like' property is " + this.like)
},
methods: {
toggleLike: function() {
} //end toggleLike
}
});
The mounted
function should print that property value, but instead I get
The value of 'like' property is undefined
Why? Is this how it works? How can I make it so I can get that value and also update it if clicked, to then do a request to my API? (I mean, I'm not asking how to do those single tasks, just where\how to implement it in this situation). Am i getting the component logic right?
Upvotes: 1
Views: 1270
Reputation: 50767
Probably a bit more verbosity never hurt:
props: {
now: {
type: Number,
required: true
}
}
Instead of using the data
function, use a computed
property:
computed: {
likes: {
get: function() {
return this.now
}
}
}
However, here comes the problem.
If you need to change the # of likes after the user clicks like, you have to update this.now
. But you can't! It's a property, and properties are pure. Vue will complain about mutating a property
So now you can introduce a data variable
to determine if the user has clicked that like button:
data() {
return {
liked: 0
}
}
Now we can update our computed property:
likes: {
get: function() {
return this.now + this.liked
}
}
However, what are we liking? Now we need another property:
props: {
id: {
type: Number,
required: true
},
now: {
type: Number,
required: true
}
}
And we add a method:
methods: {
add: function() {
//axios?
axios.post(`/api/articles/${this.id}/like`)
.then (response => {
// now we can update our `liked` proper
this.liked = 1
}).catch(error => {
// handle errors if you need to
)}
}
}
And, let's make sure clicking our heart fires that event:
<span class="entypo-heart" @click="add"> {{ now }}</span>
Finally our likes
component requires an id
property from our article:
<likes now="{{ $article->likes }}" id="{{ $article->id }}"></likes>
With all this in place; you're a wizard now, Harry.
Edit
It should be noted that a user will be forever able to like this, over and over again. So you need some checks in the click
function to determine if they like it. You also need a new prop
or computed property
to determine if it was already liked. This isn't the full monty yet.
Upvotes: 2