Planning Edit Feature0:00
We've added the ability to delete puppies. So let's follow with the next logical step, which is to allow users to edit an existing puppy. Okay, so we are going to take a very similar approach here. I'm going to add a updates button or icon button next to the delete button. And we're going to have a components that pops up a model with this time, a form inside of it. And here because there's quite a bit of UI involved in that form, uh, I will paste a snippet of code.
And here because there's quite a bit of UI involved in that form, uh, I will paste a snippet of code that is very similar to what we've done in the previous lesson and then we will talk through it and work through the important path together. But the whole scaffolding is going to be the same. It's going to be a dialogue with the trigger and then the button and then some fields. And we are just going to skip over this
and then the button and then some fields. And we are just going to skip over this so we can focus on the functionality. Alright, so in our Puppy card we had set a puppyDelete if we could delete the puppy. And so let's go Aaron Francis for a second and have some wishful thinking programming and wish that we were able to do exactly the same with update. Wouldn't it be nice if we had the ability
Adding Update Authorization1:18
to do exactly the same with update. Wouldn't it be nice if we had the ability to puppy can update that we would have a puppy update component just like so. And while we are going to manifest this and speak it into existence, I know this lesson title hints that we should focus on the front end, but I still want to go and edit the policy so that we can make this happen. And then we'll focus on the front end.
and edit the policy so that we can make this happen. And then we'll focus on the front end. So PuppyPolicy, we go and so now we are interested in the update function here. And basically we want the exact same rules to apply. So I can just copy that and I think it's completely fine to have some duplication here because really whoever can delete a Puppy should also be
to have some duplication here because really whoever can delete a Puppy should also be able to update it and vice versa. Now if you're feeling terrible about this duplication and you shouldn't, but if you do, uh, you could go down and say have a protected function that is called exactly like this isOwner or ownsPuppy and then it's going to do the work to figure out if this person is the owner. And then with that in place you could go in both places
to figure out if this person is the owner. And then with that in place you could go in both places and replace these with the this is owner and we need to pass the user and the puppy. So this is the same, but instead of having two lines of code, you now have three. So I'm going to remove that and yes, if you were to reuse that more than enough times, maybe you could consider having an abstraction. I will not write him.
Exposing Update in Resource2:46
maybe you could consider having an abstraction. I will not write him. Alright, we have a policy in place for updates. We now need to make it available on the front end. And remember we did this in the PuppyResource, the JResource. So we'll do exactly the same uh, PuppyResource this time. And where we have the delete again, copilot is going to one line, one shot it. Thank you very much. We can now update
to one line, one shot it. Thank you very much. We can now update with the exact same check. Do we have a loggedInUser? If yes, cool. Otherwise set it to false easy. Our component will still be unhappy about this scan update because we haven't updated our types, huh? Manual update, like I said ranger is gonna be cool. So here enter weight tab modern programming. So now we have the update boolean as well.
Scaffolding Update Component3:29
So here enter weight tab modern programming. So now we have the update boolean as well. And so this part is satisfied. The last thing we need to do now is actually create this puppy Update component. So we have our puppy Delete component. And so next to it, and that's why I named the component starting with puppy, we are going to have PuppyUpdate, that's TSX. And the nice thing is they're going to be co-located.
we are going to have puppy dash update, that's TSX. And the nice thing is they're going to be co-located because of the alphabetical order of files. Great. So this is the part where I fast forward with some scaffolding code, don't worry about it, we will read through it. But honestly if I was typing all of this code, this lesson would last about one and a half hour, probably maybe not, but you know what I mean.
and a half hour, probably maybe not, but you know what I mean. And we just wanna fast forward to the good bits. Alright, so through the magic of time travel in 3, 2, 1 boo whoa, look at this. We have a lot of code but like I mentioned, I'm going to walk through it with you and as you'll see there's nothing new here, no new concepts at all if you've watched the prior videos. And so we are going to be able to do the next iteration
no new concepts at all if you've watched the prior videos. And so we are going to be able to do the next iteration of the learning together, but I want you to skip through this. So let's take a look at the UI and then look at the codes that powers it. All right, so I just need to import this puppy update components that we have created. So there it is. And now our wishful thinking has happened basically.
So there it is. And now our wishful thinking has happened basically. And here we go. Well we are going to need to add a flex wrapper around this too so they look a bit better. But basically remember we have our delete model and now we have a new update model which is a similar dialogue but it has three input fields as well as the action button, the submit button that we had set before.
as the action button, the submit button that we had set before. And so we'll talk about all of that and how it's set up. I will cancel the update for now because it's not wired up anyway and let's quickly fix this by adding a flex wrapper and then dig it to the update form. So what I want here is to have a flex wrapper so that flex gap, uh, two items center and just doing this is going to work nicely.
Guarding Update/Delete UI5:35
gap, uh, two items center and just doing this is going to work nicely. But there is a little problem here you might notice. And yeah, now it's looking really good but like I said, what's gonna happen here is any User that cannot update and delete the puppy, all of this markup is going to render for every puppy even if the persons cannot delete or update. And so I think we should guard this whole block here, uh, around the ability to update or delete.
And so I think we should guard this whole block here, uh, around the ability to update or delete. So we could go puppy, can the lead and end and that would work. But obviously we have this redundant and also quite different check. So here we're in a bit of a dilemma because we are checking if a User can delete and can update, but technically these are always the same true value or false value for each User.
but technically these are always the same true value or false value for each User. As you've seen, we use the same logic. So maybe we can just decide to check if a User can update and understands that uh, that means they also can delete, maybe leave a comment or we can check both. Can a User delete and update in the check? Let's keep it simple and assume it's always going to be tied together this update and delete ability. So just use one of them for the check.
to be tied together this update and delete ability. So just use one of them for the check. So actually here I'll use puppy can update let's say only for puppy owners. Uh, so now I honestly can get rid of this check and this check again making the assumption that these are always tied together, you mileage may vary. But now with this setup, the nice thing is none of this markup, these two wrapping divs will be output with an empty container here if the user
of this markup, these two wrapping div elements will be output with an empty container here if the user cannot update and delete. Alright, as promised, I'm going to walk you through all of this code. The first uh, difference is we're not using an alert dialogue but just a normal dialogue. This is not an alert that has a critical decision that you're about to destroy a resource. Uh, so dialogue is probably more appropriate.
that you're about to destroy a resource. Uh, so dialogue is probably more appropriate. And then let's go through the different parts. We start by using the useForm hook exactly like we've done in the previous lesson to get the processing state and an action to post here. But on this one we do what we've also done for the new Puppy form earlier in this course, which is use the data, setData, and errors to be able to have form field values.
which is use the data set data and errors to be able to have form field values and then validate them and show the errors. So in the use form I pass a set of fields, we have a name, trade, an image, and then we can read these values with the data and then set the values with the set data. So that's the setup again, we manually take control of the open state of the dialogue exactly like we've done in the delete model.
of the open state of the dialogue exactly like we've done in the delete model. And then really you'll see a lot of similarities. We have a trigger which is a button with the exact same styling we've done in the previous lesson and then we have the dialogue content and then inside of it we have our form. As I promised, I haven't skipped any step on submit. Simply prevents default and it's our job here to implement the functionality.
Simply prevents default and it's our job here to implement the functionality to update the puppy. Maybe the one difference with what we've done so far is I'm using label and input fields from Chati and ui, but it's purely for aesthetics reasons and there's nothing really different to it except a set of default styles. And then here this is where we use the data and setData. So we set the value to the value that we've set here.
And then here this is where we use the data and set data. So we set the value to the value that we've set here. So it's going to default to the name and trait of the existing puppy and then unchange we update that data. So that's when we submit the form, uh, the correct updated data gets sent, this is going to happen inside here. And then for each field we check if there are errors for that field and if so we display it just like we've done in
And then for each field we check if there are errors for that field and if so we display it just like we've done in the new puppy form lesson. Like I said, there's nothing new here and hopefully you should be able to follow along and everything makes sense. So let's keep scrolling. But we've basically seen all of it. Uh, going further, we have another field, same deal value, unchange errors and the same for the image. We have an unchanged to update to the uploaded file
unchange errors and the same for the image. We have an unchanged to update to the uploaded file and if we have an error, we show it. And then finally we have our submits button. Just like before, I've used a regular button so that I can control the processing state and when to close the modal and so on. If it was the dialog action, it would close the modal, but we want to control that and I've done the exact same setup
Wiring Update Endpoint10:03
but we want to control that and I've done the exact same setup with the loading spinner while it's processing that we've seen in the previous lesson. And that is a wrap. So with all that in mind, we can now go and implement the functionality of this update form. Right now. When you submit the form, nothing happens. It prevents default and just stops. That's it. It's done. And so we need to do two things.
It prevents default and just stops. That's it. It's done. And so we need to do two things. We need to call an endpoint on the Laravel backend and then we also have to create that endpoint in the backend so that we can call it and it can do the update and return us hopefully a successful message. Alright, let's do some minimal wiring to finish up this lesson and then we will tackle the backend in the next one. So I'll go in the PuppyController and
and then we will tackle the backend in the next one. So I'll go in the PuppyController and after the delete method we want to create yet another action which is going to be the update function, indeed public function update that takes the $request and the $puppy. This is the extent of, uh, copilot we want to use. And from here we've got this and like I said, minimal wiring, we are just going to dd the hello from the update.
and like I said, minimal wiring, we are just going to die and dump the 'hello' from the update method string. And so now in our PuppyUpdate component where we have left the little to-do here, let's try to hit that endpoint. And actually I've cut a little corner. I'm not going to use post here because what we really wanna do here is a PUT request because the resource, the entry already exists.
because what we really wanna do here is a PUT request because the resource, the entry already exists and we want to modify it. So POST is when you create a new entry. If you want to update an existing one, we should use the put method. So here I'm going to change this to put and you will see later why I had POST, but for now, let's go put, and here let's try to put
but for now, let's go put, and here let's try to put a wishfully thought route called puppies that update exactly like this. And so our hope is that now the form is going to submit its data, its values to the put route. So one more piece of wiring to do, we need to go to web.php. And again, in the logged in route, just like we have store and destroy, we are going to have Route::put.
And again, in the logged in route, just like we have store and destroy, we are going to have route put. And this is going to be puppies/{puppy} and exactly like suggested, we are going to hit the update method on the PuppyController, the one we've just created. And the route is named puppies.update, which is matching this route. We're hitting in the put method. So let's cross our fingers.
We're hitting in the put method. So let's cross our fingers and hope that we've set it up correctly. If we've done right, we should see a hello from the update method, uh, dumped into the error window I guess. And that means that we can go into the next lesson and implement the backend. Let's check it out. I will go and try edit. Ellie, I'm going to change the name to Simon,
Let's check it out. I will go and try edit. Ellie, I'm going to change the name to Simon, although this is not going to do anything. And let's try to update and hello from the update method. We are good to go. All right, see you in the next video.
