در حال بارگذاری ...

مرور ساخت فرم ایده0:06

All right, so in the last episode, we added basic support for modals. I can now click on a button, dispatch an event, reveal a simple modal, and then click away to hide it. So now I wanna build the actual form to create the idea. Okay, let's get going. So here is that homepage. We dispatch the event, and then right down here at the bottom we have a modal called Create Idea. And yet this is where our form would go.

Add Store Endpoint0:29

modal called Create Idea. And yet this is where our form would go. Alright, so there's a lot to do here. The first thing we know is we're gonna have a form and to start this form, we'll submit to the proper endpoint to create a new idea. And we don't have one right now. So let's duplicate this and say, all right, listen for a post request to ideas that will hit the store action.

and say, all right, listen for a post request to ideas that will hit the store action. We'll give that a name if needed. And yes, you have to be signed in. All right, within idea controller, and actually I wanna come back to this in just a minute, but if I scroll down, this is where we would persist the idea. All right, so for now, I'll say persist to the idea, and then we will implement that at the end

Refactor Status Filtering1:04

All right, so for now, I'll say persist to the idea, and then we will implement that at the end of the video if we have time. Okay, real quick, if I scroll back up. Yeah, we covered this. Uh, this checks, if we have a status and then quickly validates or filters it to ensure that it is a, a real status that we support. Um, you know, what I would actually do in real life is I would inline a lot of this.

Um, you know, what I would actually do in real life is I would inline a lot of this. So I would say if status or let's say request status is n uh, the list of ideas, status, values, yeah. If that happens to be true, only on that condition do we apply the scope. So at that point, we would do this. All right, so think about it before we were checking status and then optionally turning it off.

All right, so think about it before we were checking status and then optionally turning it off. Now we are just optionally enabling it, right? So if we found it in this list, only then should we add a wear clause. And I think that would allow me to get rid of all of that, which is kind of irking me to be honest. And we end up with something like this. Alright, so now if I were to come back real quick pending and progress, yeah, that still works like it did before,

Build Modal Form Fields2:08

Alright, so now if I were to come back real quick pending and progress, yeah, that still works like it did before, but this is a little more to my liking. And of course we can put this on its own line. Okay, Back to our form. It's gonna submit to Idea store and the method is gonna be post. And then of course we're gonna add csrf protection. All right? So I'll do some of these manually and then I'll paste in some to save us some time.

All right? So I'll do some of these manually and then I'll paste in some to save us some time. So to start, I'm gonna add just a little bit of space, I dunno, maybe six in between each of the form fields. And yeah, we already have a field component, right? We built this and if we click through a field expects a label name, optional type. All right, label will be, well, what is the title of this idea? Name can be title. Let's give it a placeholder

what is the title of this idea? Name can be title. Let's give it a placeholder that will just be merged in. Enter an idea for your title. And then we don't have support for this just yet, but ideally this is where we would automatically focus when the modal is open. Alright, so if we were to just leave it like that, come back, click on this. Yeah, now we have this,

come back, click on this. Yeah, now we have this, but notice it's just, it's way too small. So let's make it take up a little more space on the modal itself. Why don't we say for the card, I'm gonna add a few classes. So just a little shadow. We're gonna set a maximum width, so not too wide, but then we will take up as much width as we possibly can. And then the same for the height.

but then we will take up as much width as we possibly can. And then the same for the height. So I don't want it to, to get too high where it's, it's taller than the window. So it should be about 80% of the Windows heights. But if we need to scroll that modal, we can. Okay, so now there we go. We just have a little more room to work with here. Perfect. So while we're here, I think we should also add a traditional button to close the modal.

So while we're here, I think we should also add a traditional button to close the modal. Even though you can click away, maybe we should have a close button. So I think I have an icon for that. Yes, I do. Icon close. Uh, now generally whenever you have a button that doesn't have text, but instead just an icon, you should add an aria label that will say close model, something like that. Okay, back to the browser. Open this up.

that will say close model, something like that. Okay, back to the browser. Open this up. Now we have an X and of course we need to activate it so we could say, when you click on it, let's set. Show to false. Come back, open this up, click on it, it hides. Alright, next, let's set a class of flex here. And once again, justify between. So this is another scenario where I want the heading on the far left

So this is another scenario where I want the heading on the far left and the button on the far right we'll do item sensor. And then on the main content, let's just push it down a little bit. A little march on top. Yep, there you go. New idea. Here's your title. Close it out, it works fine. The next field I wanna add is for the description, right? And I'm just kind of going down the list, by the way, for ideas to make an idea,

And I'm just kind of going down the list, by the way, for ideas to make an idea, we need a user, we'll do that automatically. But you need a title, a description, a status, eventually an image path, uh, and then links. And then we'll also add steps. So we're gonna keep coming back and working on this. All right, so I'll paste this one in. Yeah, so we have a description, uh, placeholder. Ideally I'd like this to be a text area itself.

Add Textarea Support5:18

Yeah, so we have a description, uh, placeholder. Ideally I'd like this to be a text area itself. So if I open this up though, we don't have support for that. It just renders as an input. So that won't do. So let's see what we can offer. So let's do a couple things here. Let's do a little cleanup First, I'll put these attributes on their own line, like so. And then why don't we make this as, uh, configurable as possible?

And then why don't we make this as, uh, configurable as possible? For example, maybe sometimes you don't need a label at all. In that case, we could say label is optional. And then we can check, did you give us a label only on that condition? Do we render this? Next? I could say, well, if the type is, uh, a text area, so maybe, um, if type equals text area.

so maybe, um, if type equals text area. Well, in that case, we of course wanna render this mostly as a text area. So we'd have something like this, just like before. We might even be able to merge the text area and the input, but maybe not. Uh, we're gonna give it a class of text area, put these on their own line, let's merge in any attributes. And then what we can say is, all right,

put these on their own line, let's merge in any attributes. And then what we can say is, all right, well if we don't have a text area, then it's just assumed it's a basic input. So maybe I could do else in that case and then end if, alright, the only remaining thing is to set the old value. So in this case, I could say, uh, old name. Alright, let's come back, click on this. And now we get a full text area. This is what I want.

Implement Status Selector6:40

Alright, let's come back, click on this. And now we get a full text area. This is what I want. It's looking great. Alright, back to work. Alright, so next, why don't we tackle the status. And I want this to be, uh, a little more intricate. I want them to be three buttons where you can click the button to choose which status you want to apply. And then maybe a behind the scenes that will set a hidden input

And then maybe a behind the scenes that will set a hidden input and that value will be submitted to the form. So yeah, this will be a little bit custom. So with that in mind, I'm just gonna do a basic div here. I know I want a label. This is gonna be for the status. I'm gonna give it a class of label and the value will be status. All right, have a look. There we go. Cool. Next, yeah, like I said, I want three

All right, have a look. There we go. Cool. Next, yeah, like I said, I want three buttons just like this. So probably using a grid or flex box maybe right here. We'll have a diviv, set it to flex, put a little space in between. And then I'm gonna loop over the available idea statuses. And for each one render a button, right? So once again, we would do, uh, app idea status. Give me all of the various cases and we'll call that status.

So once again, we would do, uh, app idea status. Give me all of the various cases and we'll call that status. And then, yeah, within here we would just render our button. So this would be the status label. Alright, let's see what that looks like. Come back, open this up. And now we have three unsigned buttons, but it is working. Okay, so on the button itself, let's apply some, uh, simple classes. So once again, it'll get that button styling, it's going

let's apply some, uh, simple classes. So once again, it'll get that button styling, it's going to flex so it can fill or or contract to take up what space it needs. And I'm gonna force a height. There we go. Sorry, just needed a refresh. Okay, but now notice, because they're all green, it feels like they're all selected. So it sounds like I need to conditionally add something,

it feels like they're all selected. So it sounds like I need to conditionally add something, like a button outlined attributes. So here, yeah, this would signal not selected and the primary view would signal selected. Alright, so with Alpine, and it sounds like this should be treated as an alpine component. What I'll do is on the form itself, I'm gonna declare that to be our Alpine component, okay?

What I'll do is on the form itself, I'm gonna declare that to be our Alpine component, okay? So remember if you want any kind of interactivity, if you want data binding, if you want event listeners, if there is no X data on the element or one of its closest parents, then it's not going to work. Okay? So here now I can do data binding with Alpine and I'll say, I'm gonna conditionally apply a class. Alright? But before I know how to apply that class, I need to know which one was selected, right?

Alright? But before I know how to apply that class, I need to know which one was selected, right? I need a way to listen for did you click on this or this or this? And of course that's being treated as a submit button. So let's come back and we'll say, alright, this is a simple button, don't respond to submit events or anything like that. And then let's format. And then here I can say, okay, well when you click on me, it sounds like we need to store

And then let's format. And then here I can say, okay, well when you click on me, it sounds like we need to store what the status should be. So the selected status will be, hmm, this value. So once again, we could do like status value and then try to wrap that in a string. Don't forget that gets a little weird and wonky when we're doing it this way. So we can just use the js directive status value.

and wonky when we're doing it this way. So we can just use the js directive status value. Okay? So remember we're we're having a single source of truth. We're gonna store what status the user selected, uh, by listening for when they click on the associated button. And then it updates this value on your component. So now I can say, all right, the status, and we'll start with pending. This is the initial status. Okay?

and we'll start with pending. This is the initial status. Okay? So, uh, here's what I'll show you maybe right here. Let's do x text to the selected status. Come back, open this up, and the selected one is pending. But notice if I click on completed, then the selected one that we're tripling here, uh, is set to completed. Cool. Now we have a way to track that and uh, respond. For example, I could say, well once again, paste this in. If the current status, uh,

For example, I could say, well once again, paste this in. If the current status, uh, that the user has selected is equal to the one in the loop, well then, then do nothing otherwise set a button outlined. Um, class. All right. So now if I come back, we open this up and sure enough, by default pending is selected. But if I swap this out, it updates. All right? Pretty simple. It it's not that complicated.

But if I swap this out, it updates. All right? Pretty simple. It it's not that complicated. By the way, another way you could write this is with, um, again, some alpine learning here. I bet you didn't expect is we could use an object syntax. So I could say, all right, apply the button outlined, um, class on the condition. That status does not equal the current value. And yet this would give me the exact same thing. All right? And I actually, I think I like that a tiny bit more. Cool.

And yet this would give me the exact same thing. All right? And I actually, I think I like that a tiny bit more. Cool. All right, so now think about what we can do here. Uh, after the, for each we can have an input and we can bind its value to whatever the current status is. And that is what's going to be submitted to our server. All right? So for example, if I said name is status value, and we bind that to the currently selected status, well it's not hidden at the moment, so you will see it. But um, where is it? Oh, there it is.

well it's not hidden at the moment, so you will see it. But um, where is it? Oh, there it is. Let's just make it crystal clear input. Alright, one more time. Open this up. Here's our input. And notice this is the value that's going to be submitted to our server. Cool. But of course we don't need to see it, so we're gonna say hidden. Alright, so we just created sort of an elegant way to let the user select their status while

Alright, so we just created sort of an elegant way to let the user select their status while behind the scenes we're making it work, uh, when we submit the form to the server. Alright, so notice there's a little spacing here. Uh, let's go ahead and let's see what field does. 'cause we're sort of doing our own thing here. We might even wanna do like a field wrap, um, component, but that's okay. Space Y two add a little space in

component, but that's okay. Space Y two add a little space in between the label and the diviv. Cool, I think that looks pretty good, don't you? Finally, uh, we should handle errors here. So let's see what we're doing for field. Uh, we're just hard coding that that could be its own component as well. Um, but I won't do that until I have a recent to. So we'll have our label, our diviv here

Um, but I won't do that until I have a recent to. So we'll have our label, our diviv here and then a paragraph for the error. And you know what, actually as I say this, I think I should extract this 'cause this is just cumbersome enough. Yeah, I think so. Alright, so let's go into form. I'm gonna grab this, create a new file, error up blade, a PHP, paste it in, make it dynamic. So you gotta give me a name. That looks good.

a PHP, paste it in, make it dynamic. So you gotta give me a name. That looks good. Okay, so now on the field itself, this can delegate to our error component like, so I think that's right and then I can do the exact same thing here. Okay, so I know we have some more things that need to be added, but let's have our footer links here. Um, so once again,

have our footer links here. Um, so once again, we're gonna have buttons that go to the very end. We'll have a little space in between the buttons and then what do we have here? Um, maybe one to cancel and then maybe one to create. Yeah. So of course the one to create will be explicit, has a type of submit. This one has a type of plain old button. Now submit, of course we'll have a traditional button

This one has a type of plain old button. Now submit, of course we'll have a traditional button styling, but maybe cancel will be like a ghost styling or a text styling. Let's see what that looks like. Open this up and yeah, I think a little space should go above it though, so maybe I could out of margin of course, but maybe this should go up here. Come back. Maybe that's okay. I'm not sure we'll check it, but I think that's okay.

Come back. Maybe that's okay. I'm not sure we'll check it, but I think that's okay. Okay, So now I know when I click on create this will submit it to the server, but notice I immediately get a 4 0 3 and I don't have any kind of client side, uh, validation. That's something to think about. So let's do this. Um, maybe you could assume that any input is required, but it's actually that's not the case. So instead we could be explicit.

but it's actually that's not the case. So instead we could be explicit. And actually as it turns out, the way I wanna structure this, only the title itself is required. Everything else is optional just to get you going as quickly as possible. So if I were to come back and refresh, you'll see that now I can't even submit the form without

and refresh, you'll see that now I can't even submit the form without filling out a title. Good. Now what should happen when the user cancels? Well, this is an indication we should maybe reset the form and hide the modal. So what we might do is say, okay, well when you click on me, let's dispatch our own event that we want to close the modal. So once again, dispatch close modal, all right?

to close the modal. So once again, dispatch close modal, all right? And that's gonna bubble all the way up. Uh, all the way to the where are we? All the way to the modal itself. The modal is gonna listen for that. So let's say listen for close modal and close our sanity check. One more time, cancel. And we pick up on that. Okay, so now once again we can just set show to false,

Authorize, Validate, Persist15:58

One more time, cancel. And we pick up on that. Okay, so now once again we can just set show to false, open it up, cancel, open it up, cancel. It works. Alright, so now I just wanna get this to process as quickly as possible. So what if I provide a title and I submit it? You'll notice we're getting a 4 0 3 and we did run into that. So if I come back to idea controller, where we store the idea, um,

So if I come back to idea controller, where we store the idea, um, notice it is typing store idea request. And by default the generator will not authorize it just as a security precaution. So we can return true here or we can not use a form request at all. We could do it in line again, you just pick what you wanna do. Here we can keep it.

you just pick what you wanna do. Here we can keep it. So right down here I'm gonna paste in just a handful of rules just to save us some time. And it's all a recap. So to create a new idea, a title is required, everything else is knowable. So description should be a string. We can add some maximum lengths if we want. If you wanna be super explicit, of course you can do things like this.

If you wanna be super explicit, of course you can do things like this. Uh, the status, uh, can be knowable, uh, but if it exists, it should be included in this list. Or really maybe because there's always a default status, we should make this required. Yeah, maybe we should do that. I think that, I think that would work. So let's give it a shot. Let's go back to idea controller.

I think that, I think that would work. So let's give it a shot. Let's go back to idea controller. And we're gonna die and dump the request all and see if we have everything we need. All right, some new idea create and sure enough, we have the title and the status. No description, but that's fine because it's nullable. Perfect. Okay, so now how do we quickly create an idea? And actually this will get a little bit more complicated, but at least to start we'll say ideas

And actually this will get a little bit more complicated, but at least to start we'll say ideas for the user, create a new one. And again, to start, let's just pass the validated attributes, uh, that we have here. Okay, so when we're done, we will return a redirect to the route of, uh, idea index. And let's give a flash message with success idea created. All right, good. Let's give it a shot.

And let's give a flash message with success idea created. All right, good. Let's give it a shot. So here is my new idea. I'm currently working on it. Create it and it shows at the bottom. But actually I'd like to see that at the top. So an ideas controller. You can see how easy it is to work on things like this. I can say, give me the latest ones ordered by, uh, the created at timestamp. Alright, come back, give it a refresh.

the created at timestamp. Alright, come back, give it a refresh. And now the most recent ones come at the top. Perfect. I can delete this. Looks good. Let's create another one. Some new idea about buying a property, something like that. Create it. And there we go. Everything's working, but there's actually still quite a bit of work to do. So let's keep going in the next episode.

So let's keep going in the next episode.

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