تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Adding Post Like Button0:00

So, I'm thinking we can add our like button just here underneath the like counter on the post show page. Let's jump into our Vue component, here we go, here's the counter. We could add a wrapping div, and we need some form of form to submit this like request to the correct endpoint. This is actually incredibly easy with Inertia, because the Inertia link component makes it trivial to create single button forms, so we'll pull in that link component, and I want to set the href equal to our store root, so that would be likes.store, and remember we have those two different parameters, the first is what's the type, well the type is going to be post, the second is what's the id, that would be post.id, and then in order to set

have those two different parameters, the first is what's the type, well the type is going to be post, the second is what's the id, that would be post.id, and then in order to set this up as a fully functioning single button form, we pass in a method, the method for storing is post, and that's it. Let's say that this is for liking the post, we'll come back, I'll hit that button, and you can see the like counter actually incremented by one, in other words, it worked flawlessly. Now it's a little ugly at the moment, we could add an icon to spruce things up, so here's heroicons.com, let's search for, yeah, hand thumb up I think will do us just fine, so if we go back to our id, we'll need to pull that in, we'll go to our imports here, and I can say import, hand thumb up icon, let's have the solid variant here, so maybe 20 solid,

if we go back to our id, we'll need to pull that in, we'll go to our imports here, and I can say import, handThumbUpIcon, let's have the solid variant here, so maybe 20Solid, and while we're here we can also import the handThumbDownIcon, because we'll need our unlike button as well. Okay, back up to the top, where have you gone, here you are, let's add in that icon, so handThumbUpIcon, we could say that it has maybe a size of 4, and then all the rest should be classes on the button itself. Maybe we could say this is an inline block, why don't we give it a background color, background, maybe by default it's indigo-600, and then when you hover, we're gonna set the background to pink-500, we could add some transition here, so transition-colors, so that it kind

maybe by default it's indigo 600, and then when you hover, we're gonna set the background to pink 500, we could add some transition here, so transition colors, so that it kind of fades nicely rather than being a jagged and instant change, and then maybe text is white so that it's nice and clear, what would that look like, okay, it needs some work but we're getting there. Let's maybe say py-1.5 px-3, and we'll need to make sure that the button is inline, let's do that, so inline-block, nice, and then why don't we go for rounded-full, let's live a little, yeah, rounded-full should give us a nice pill shape, cool, that looks good, I might just add a little spacing between the icon and the text, nice. Now if I try to like this again, note that obviously I've already liked this post once,

Implementing Unlike Toggle3:01

I might just add a little spacing between the icon and the text, nice. Now if I try to like this again, note that obviously I've already liked this Post once, I'm gonna get a 403, we definitely don't want that to happen to the user, so we also need an unlike button, for now let's copy and paste, so here we go, we'll drop this in, we'll change this to unlike Post, we want to go to likes.destroy, the method will be delete, but everything else should be the same other than the fact that we want to change the icon, yeah, here we are, so we have like Post and unlike Post, and now, look at that, you can see the counter changing as we move between the two, again, of course, if I try to unlike the Post twice, I get a 403, so in reality, we should conditionally show these buttons depending on whether we are able to like the Post or not.

Conditionally Showing Buttons3:47

to unlike the Post twice, I get a 403, so in reality, we should conditionally show these buttons depending on whether we are able to like the Post or not. We could do this using the same methodology we've used for our Comment resource, in other words, we could have a can array where we check those permissions, so if we go to the Post resource, let's head down to the bottom and add a little can array, and I'd want to say, well, am I actually allowed to like a particular Post? The answer would be, well, for the given User, and again, that User might not exist, so let's make it optional, can you go ahead and create the like fully qualified class name passing in this resource, which in this case would be an instance of a Post model. Then on the front end, let's introduce a little v-if, so v-if post.can.like, then of

in this resource, which in this case would be an instance of a Post model. Then on the front end, let's introduce a little v-if, so v-if post.can.like, then of course, we'll show the like post button, but otherwise, we'll use a v-else, and we'll show the unlike post button. Let's refresh, like, unlike, like, unlike, how cool is that? Works like a dream, and Inertia makes this kind of stuff so, so simple because of the power of that link component. Let's add a little margin top, class mt-2 perhaps, yep, just to give it a bit of spacing, and we're off to the races. Now one thing to note, if we go to the post index, and we look at view dev tools, let's

Optimizing Permission Checks5:13

and we're off to the races. Now one thing to note, if we go to the Post index, and we look at view dev tools, let's jump into view, index, posts, data, of course, all of these posts are now going to have this can array, which means that for every post in the index, we're performing an exists check, but we're never going to actually have the functionality to like a post from the index. Only once you click into a post, can you like or unlike it. So we're sort of wasting computation and SQL queries here, I want to fix that. In order to fix it, why don't we add a little helper method to our Post resource here. So something like public function, and maybe you say withLikePermission, which returns an instance of itself.

So something like public function, and maybe you say withLikePermission, which returns an instance of itself. So essentially, we can tag this on inside our controller. In fact, let me do that now. We'll head into the PostController, we'll jump into the show method. And yep, here, why don't we say withLikePermission, like so. Now withLikePermission should probably set a property to true on the resource itself. So this withLikePermission is going to be set to true. And of course, we'll have to actually add that. So declare a property, it can be private, the default is false, in other words, by default,

And of course, we'll have to actually add that. So declare a property, it can be private, the default is false, in other words, by default, it will not include the permission. And I'll remove this comment that PHPStorm generated for me. Okay, so with this little helper method in place, I could now use that when helper that we've discussed in previous episodes. So only include this property when this withLikePermission is set to true. Otherwise, don't perform that computational step at all. If we now go back to our Post index, and we refresh, let's take a look inside data[0], see that the can array is empty, because we haven't included that helper method inside.

If we now go back to our Post index, and we refresh, let's take a look inside data[0], see that the can array is empty, because we haven't included that helper method inside the index of our PostController. But click into one of these posts. And then let's refresh the data that's being passed here, show, we should have our post. And the can array is an object where like is set to true and liking and unliking works exactly as you'd expect. So that's a really nice way to save those extra SQL queries that we just don't need to perform. We can keep our app feeling nice and snappy as it expands.

Adding Comment Like Buttons7:38

to perform. We can keep our app feeling nice and snappy as it expands. Right, so that's liking post complete. Let's copy and paste this over to the comments that we have on a post. I'm going to shamelessly copy and paste the like button we've just created. We'll jump into our CommentView component. And where we have our actions here for editing and deleting, just above, I'm going to drop this in. We don't need to add any margin top, so I'll remove that. And of course, we'll just need to update a few parts of these buttons to actually fit

We don't need to add any margin top, so I'll remove that. And of course, we'll just need to update a few parts of these buttons to actually fit the use case. So we're interested in Comment, can.like. We still want to go to likes.store, but this time we're interested in a comment and we're passing the comment ID. Method is still post. We're probably going to change the look and feel of this in just a moment. We're not liking a post, we're liking a comment. And in fact, I think we need to possibly wrap this in an srOnly span, because it needs

We're not liking a post, we're liking a comment. And in fact, I think we need to possibly wrap this in an sr-only span, because it needs to be smaller. Obviously, we have less space to play with in a comment index. So let's go ahead and do that. And then we'll translate these into the unlike version at the bottom as well. So this will be unlike comment. We'll change this back to the hand thumb down icon. We have likes.destroy. This becomes comment.

We have VLs, which is fine, likes.destroy. This becomes Comment. This is going to be comment.id. Method is delete. We'll leave the classes in. Yeah, okay, let's see how that looks. It's pretty ugly. We need to make some changes. Let's alter some classes here. So maybe we'll get rid of the background colour.

Let's alter some classes here. So maybe we'll get rid of the background colour. We'll leave it as inline-block. When we hover, why don't we set the text to pink-500? And by default, why don't we have the text as maybe grey-700? We'll get rid of text-white, because that no longer makes sense. That's a duplicate. And we'll get rid of the padding as well. We also don't need to say that it's rounded-full anymore. Let's see how that looks.

We also don't need to say that it's rounded full anymore. Let's see how that looks. There we go. That's a lot better. Now, the reason it's showing that thumbs down icon is because we don't have this like property in the comment can array. So obviously, it's going to say, well, that must mean you're not able to like. The $is is truthy. So let's go ahead and add can.like to our comment resource. We'll jump into CommentResource.

So let's go ahead and add can.like to our Comment resource. We'll jump into Comment resource. We can come down here and say, well, can you like it? And let's jump into the Post resource here, because I essentially want to do exactly the same thing. So we'll copy that line and paste it. Of course, we'll need to add the withLikePermission helper and the little property to the class. So we'll come in and copy that as well. And we'll drop that on our Comment resource.

So we'll come in and copy that as well. And we'll drop that on our Comment resource. And then let's go to the PostController. We're still interested in the show method. And of course, we want to tag this helper onto the end of Comment resource collection. Let's do that. Now, if you come to the front end and refresh, you're actually going to get an exception. And the exception is that withLikePermission does not exist. You may think, well, we just added withLikePermission. What's going on?

Fixing Collection Permissions10:44

You may think, well, we just added with like permission. What's going on? The problem is that we're not actually dealing with a Comment resource here. We're dealing with an anonymous resource collection. So essentially, because we have not one Comment, but a collection of comments, Laravel is wrapping that up in this anonymous resource collection class. And we're dealing with an abstraction on top of the Comment resource. So we're going to have to do a little bit of playing around if we want to be able to make use of this with like permission helper. Let's first convert this to a standard closure.

make use of this with like permission helper. Let's first convert this to a standard closure. I'm going to assign commentResource to its own variable. commentResource equals CommentResource::collection. And I'm going to remove withLikePermission for now. Okay. I'll return commentResource. And in the middle here, we're going to do a little bit of work. If you take a look at the AnonymousResourceCollection, you'll note that it actually has a collection property, which is the underlying instance of all of the individual Comment.

If you take a look at the anonymous resource collection, you'll note that it actually has a collection property, which is the underlying instance of all of the individual Comment resource items. So we want to go into each of those items and transform them by calling that helper method that we created. Well, there is actually a method for that on a collection called aptly transform. The difference between map and transform, in case you're wondering, map is immutable. In other words, map is going to return a new collection instance, whereas transform is mutable. It will change the existing collection instance.

mutable. It will change the existing collection instance. Seeing as this is a property on a class that we don't control, that's exactly what we want to do. So we'll pass transform our closure. It will accept the individual Comment resource. And then we can call resource with like permission, like so, in order to instruct that particular resource to include the like property inside the can array. Let's see if that works. Well, now our front end does load, which is a good sign.

Preserving Scroll Position12:41

Let's see if that works. Well, now our front end does load, which is a good sign. And if we come down to the comments at the bottom, you can see that the like button is now there instead of the unlike button, which must mean that the correct data is being loaded. Let's go ahead and click the like button. It kicks us back to the top. We can fix that quite easily. Let's come back to our CommentView component. And on the link here, you can add this to both of the components. You just want to add an attribute called preserveScroll.

And on the link here, you can add this to both of the components. You just want to add an attribute called preserveScroll. And that will instruct Inertia not to change the scroll position when it makes this request. So now let's attempt to unlike this comment that we've just liked. And sure enough, it works. The scroll position maintains. And as you can see from the counter here on the left-hand side, it is actually changing. We are successfully liking and unliking this comment. So how cool is that? I think that's pretty awesome.

Hiding Buttons for Guests13:34

So how cool is that? I think that's pretty awesome. There's one last edge case we need to check for with this functionality. If we log out of our account, and then let's go to /posts, because obviously guests can see posts, we still have the like and unlike buttons. And if you attempt to call them, you're going to get an exception. It's not going to work. But we don't want to show this to the user. We just don't want to show them the like or unlike button at all. This is fairly simple to fix.

We just don't want to show them the like or unlike button at all. This is fairly simple to fix. Let's go to the div that wraps our buttons. And we can say only show this if page.props.auth.user actually exists. And you'll see in this instance, the actions for liking or unliking comments have disappeared. Let's copy this v-if statement. We'll go to PostShow, and we'll add the exact same v-if to the div here. And now the like and unlike button has disappeared. Let's go ahead and log back in as our ExampleUser. And you'll see that the like and unlike buttons are back, both on posts and comments.

Let's go ahead and log back in as our example User. And you'll see that the like and unlike buttons are back, both on posts and comments. So I really like how easy Inertia makes adding things like this, those single button forms that you will have all around the place inside an application like this. The log out button is another example of where Inertia makes this super simple. And with that, we have like and unlike functionality baked right in for comments and posts in our forum application. Super cool, hey?

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟