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

Reducing Modal Duplication0:00

We now have this added Modal component that we're using on both the index and the show page. But actually on both pages we still have a lot of repeated code. So we are importing this added Modal component. We are keeping track of the editingUser state at the bottom of this page. We're using that component and passing the user. And then we have these click and close events to set the state of editingUser.

And then we have these click and close events to set the state of editing User. And all of this code is not, is needed on each page that you ever want to use the model alone. So wouldn't it be great if we have one component that we can use to open a model? So actually something similar like link the built-in components from Inertia where we just pass a backend route and that component would take care of opening the model and that's what we are gonna build.

Building ModalLink Component0:47

and that component would take care of opening the model and that's what we are gonna build. So we are gonna replace the regular HTML button with a model link component. And instead of setting an editingUser state a local state, uh, we are just gonna pass it the href from the link above. So the same users edit route gonna remove this one and then we need to create that component. So let's do that ModLink. And this component should be really simple,

So let's do that mod link. And this component should be really simple, so it should just accept an href prop. So let's start with that. Define props, href, which is gonna be a string and it's gonna be required. And then in the template we want to render a button element. You set the type to button as well. When you click on it, we want to do something like open the href, whoops.

When you click on it, we want to do something like open the HF, whoops. And then we want to render everything that's passed in from the parent from the index page. So that would be the slot. And let's see in the browser, if there's still rendering, yeah, that still works. So we still have um, our title here, editor modal and the classes are passed down. So that works. But then in this modal link component,

Creating useModal Global State2:04

and the classes are passed down. So that works. But then in this ModalLink component, we need to introduce some kind of global state. Actually not in this Link component, but from within this Link component. We need to set some state that's also accessible from other components because other components should know that there is a modal opened. And let's do that with a new file.

that there is a modal opened. And let's do that with a new file. And we are gonna call that file useModal and that's gonna hold our global state of the modal. And this file is not really a composable, uh, because it has some global state so you can't reuse it, but it's more like a surface or a utility. Let's start with adding a modal ref. Let's import ref from vue and then we can add some functions.

Let's import ref from view and then we can add some functions. So first, an open function which is gonna accept an HF. And this one is gonna make the backend request and set model value. And then we have a close function and that one is just gonna set model value back to null. Then we are going to export those three. So model, open and close. Let's hit save. And then in modeling we are going to use that method.

So model open and close. Let's hit save. And then in modeling we are going to use that method. So we are going to import it again, import open from our use model file. And you know what? In open, let's dump it out to the console. So let's log it opening modal with URL Ty A in. Let's open the console lock, click on editing modal. And there you can see our log message with the full URL.

Mimicking Inertia Requests3:50

Let's open the console lock, click on editing modal. And there you can see our log message with the full URL. So that works. Next up I want to take a look at an actual Inertia request. So what happens when you click on a link component like edit? Let's open a network tab, click on edit. And there you can see a single request. So Inertia is known for its single page application capabilities.

So Inertia is known for its single page application capabilities. Uh, it's not a full page request, so we're just getting adjacent object back from this request. Let's check out the response here You can see the JSON object with a component with the props. So here we have that user object and we have some shared props like errors and status. And what's also good to know that in our headers

and we have some shared props like errors and status. And what's also good to know that in our headers that we are requesting here request headers, you can see that we have this x-inertia header which is set to true and we want to mimic this behavior when we are requesting our model component from the backend. So let's do that in that useModel file. So here instead of on, so lock we're gonna use axios. That's also used by Inertia under the hood.

So here instead of on, so lock we're gonna use axios. That's also used by Inertia under the hood. So that's not some new dependency that we need. Uh, axios, uh, we are gonna request this Hf but with some additional options. One of those is headers. So here we're gonna set X-Inertia to true and let's also pass in X-Modal so that we know in the backend that we are not only doing an Inertia request but also that we specifically ask for a modal.

in the backend that we are not only doing an inertia request but also that we specifically ask for a modal. Then let's import XOs from the XOs library like this. And lastly, when this request is successful, let's dump it out. So response for now, I'm just gonna lock out the response data it saves so it reforms. And let's do some backend work. Let's search for UserController. And scroll to the edit page to the edit method.

Backend Modal Response Handling5:55

Let's search for UserController. And scroll to the edit page to the edit method. And here you can see that it normally renders this user/edit page. So that would be this one. But if we are requesting a modal, which we know because we are sending that X-Modal-Header, then we want to return this added modal component. So in here we are gonna check if our request wants a modal. So I'm gonna use the request instance.

So in here we are gonna check if our request wants a modal. So I'm gonna use the request instance with this request helper, um, header and then X-Modal. And if that one is present, just gonna set it to true and otherwise to false. So in here if it wants a modal, let's return user/edit/modal. And otherwise it's gonna be uh, user/edit. And while we're editing, I wanna do a small refactor and move this to uh, macro so

And while we're edit, I wanna do a small refactor and move this to a macro so that we can reuse it in other places because we are probably gonna use it in other controller methods and maybe on other spots as well. So I'm gonna copy this code, search for AppServiceProvider, and let's use the register method. So here I'm using the request object from Laravel and let's add a macro, let's also call it onceModal. Then we're gonna use a callback, let's pass in the code.

and let's add a macro, let's also call it onceModal. Then we're gonna use a callback let's pass in the code and we just gonna return it from here. So return, and instead of using the request helper, we're just gonna reuse this. So if we are calling this macro, we want to know, uh, if this request has the header and then we return true or false. So then in our controller we can use request onceModal and actually just use it directly in here.

So then in our controller we can use request once modal and actually just use it directly in here. Let's clean it up a bit. Yeah, so let's go to the browser. Let's refresh and open the inspector edit IM model. And there you can see that we're now making an HX request. So we are requesting the edit page, so that's fine already. Let's check out the request headers. Here we have X-Inertia and X-Modal, so that's fine too. And then in the response we are getting our added modal back.

Here we have Inertia and modal, so that's fine too. And then in the response we are getting our added modal back and as a props we are getting the user and we're also getting these shared props. So error status and auth, but actually we don't want them for the, for this modal. So where do they come from? There is this handleInertia request middleware, that's a part of Breeze and JetStream and it extends the default Inertia middleware.

that's a part of Breeze and JetStream and it extends the default Inertia middleware. It has this share method and there you can see that the status and the auth object is shared. Um, and actually the parent share method has that errors object. So what we wanna do here is if our request wants a modal, so we are already reusing that macro, then we just wanna bail out.

if our request wants a modal, so we are already reusing that macro, then we just wanna bail out and return an MT array. So let's try that again. Edit a modal, let's inspect its response. And now we only have the user in the props, so that's great. We now have a backend request that returns the correct information. Now let's show the modal in the front end. Let's go back to useModal.

Now let's show the model in the front end. Let's go back to use model. And what we wanna do here is set the model state based on the response data. So let's go back to the browser and check out that response one more time. Uh, we have our props and we have this component string. And what we wanna do is actually kind of resolve the string into a real view component. That's also what Inertia does when you request the page.

of resolve the string into a real few component. That's also what Inertia does when you request the page. So let's check out how it does it. Let's go to app.js. So this is where your Inertia app is created and it needs some kind of resolver that accepts a name and then it resolves the page component. And this method is part of the AV file feed plugin. Um, you don't need to worry about that right now. I'm gonna show it to you in a minute. But actually this is the code that we need.

I'm gonna show it to you in a minute. But actually this is the code that we need. So you give the name and somehow it figures out from the pages directory right here, which component we need. So let's grab it. Let's go to useModal and let's import it here. Let's import this one. Let's paste it. Whoops, into here. So instead of name, we are going to pass response, do data, do component.

So instead of name, we are going to pass response, do data, do component. And this method is a promise. So we can chain then, which is going to give us the component and then I'm gonna dump it out in the console to see what it looks like. Yeah, just like that. Let's refresh, let's go to the console. It edits, IMModal.

let's go to the console. It edits, IM modal. And there you can see that we are getting an object with a default key. And that is our actual component. So here you can see that it has figured out where this component is located. You can see the events, the props, uh, this is some internal few stuff that you don't have to worry about, but this is what we are going to need.

this is some internal few stuff that you don't have to worry about, but this is what we are going to need. So let's go back to use modal. What we are gonna do is set the modal state. So modalValue is uh, equals responseData. So we're just gonna pass everything in. And then we are also gonna set some additional key. So something like resolvedComponents equals components. 'cause this is the one that we wanna, uh, store

Rendering Modal in Layout11:42

So something like resolvedComponents equals components. 'cause this is the one that we wanna, uh, store and save for later. So let's hit save. And now let's figure out where we want to render the model. So we don't want to render it on a specific page like index.view or show.view, but on a more generic page or a more generic component like a layout. So in this case we're gonna use the authenticated layout file.

So in this case we're gonna use the authenticated layout file. And what I wanna do is render the model above all the content. So right here, let's figure out how we can do that. Now remember, in the useModel file, we are not only exporting the open and closed method, but also the model itself. So we are going to import that in our layout file. So import modal from our useModel file,

So we are going to import that in our layout file. So import Modal from our useModal file, and then we are going to use that component to render it here. So Modal do resource components and remember that it only had one key, which was default. Um, we want to render this with only if we actually have a model. So if this is now, of course, we don't want to render anything and we want to use feeBinds.

So if this is now, of course, we don't want to render anything and we want to use fee binds to bind all the molo props to the component itself. So let's hit save and see if this works. Let's refresh edit the model. And sure enough, let's close the console. Here is our model; still doesn't work quite well because our forms are not filled in, and I think the cancel button doesn't work, but we can fix that.

and I think the cancel button doesn't work, but we can fix that. So let's continue. Let's start by fixing the closing of the modal. So our added Modal component has this close event that's emitted when it wants to close and we can use it in a layout. So on close we want to close we want to call the close method. They were that we are exporting from this usedModal file. So we are resetting the global state to null.

They were that we are exporting from this used modal file. So we are resetting the global state to null. And then because we have this fee, if it should go away, let's go to the browser and see if it works. Edit a modal it cancel. And that works. The animation is not there yet, but we can fix that later on. Let's fix the fields. So in editModal we have these empty strings for name and email when we, uh, set up the component and then we watch for this user prop.

strings for name and email when we, uh, set up the component and then we watch for this user prop. But this user prop actually doesn't change. We don't have to watch it. It's already there when we mount a component. So we can do two things. Uh, we can copy this into here or we can add an additional option to the watcher. Set it to immediate. So immediate equals true. Let's see if that works. Edit a model.

Set it to immediate. So immediate equals true. Let's see if that works. Edit a model and here are our fields. Let's check if validation works. Yeah, that's still fine. Let's try to update it. Maybe 1, 2, 3 here. Update. And that works as well. So that's really great. Uh, we now have a backend model. Let's see if we can implement it on another page. So we are now on the index page. Let's go to that User profile.

So we are now on the index page. Let's go to that User profile where we also implemented the model, and let's replace that one with a model link as well. All right, let's go to the show page. And instead of our button here, we're going to use our new ModalLink component. I'm gonna grab the url from here, the href, base it in and remove the click event. Let's hit save and see if it works.

and remove the click event. Let's hit save and see if it works. Let's open the inspector hit's, edit a modal. And here you can see our backend request. And let's open a few dev tools. Here we have the show page that uses the authenticated layout. And then here at the bottom you can see that it has mounted the edit modal. But here you can see, still see the old one.

that it has mounted the edit model. But here you can see, still see the old one that's on the edit page itself. So let's clean up a bit. We can remove this one. And then in a script setup block, we can remove the state and those two imports. So the ref and editModal, we can remove. Let's try that one more time. Edit and Modal. And then here it is. And the other one is gone. And you can see if I hit cancel

And then here it is. And the other one is gone. And you can see if I hit cancel that the added modal component is gone from the tree. So let's do the same on the index page. Let's remove the previous added modal component. Let's remove the state and the two imports. So now we have a really clean solution to open modals. We, we just need this ModalLink component, which behaves the same as the Inertia Link component and that used Modal file.

which behaves the same as the Inertia link component and that used modal file. This one, that one keeps track of the state and that shares the modal with our layout. So let's see if we can take it one step further in the next episode.

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