K3nzie
K3nzie

Reputation: 465

VueJs + Laravel - like button component

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

Answers (1)

Ohgodwhy
Ohgodwhy

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

Related Questions