Laravel 11 once helper0:00
Alright, I want to upgrade our Vue version to 3.4, but I know the protests. How can you upgrade to Laravel 11 and not use one of the new features? So we'll make a quick tweak to our PHP code, and then we'll move on to Vue. In our PostFixtures class, we have this fixtures property, which we're using for memoization. That is, we're performing this slightly computationally expensive calculation, and we're storing it in this property so that on subsequent calls to getFixtures, we just return the cache. In Laravel 11, we received a new once helper for this. So instead of having to set up a public static property on the class, we just call once, we pass a closure, that closure returns the result of the method, and now we can get rid of the property entirely. The result is the same. It's a little bit cleaner, which is nice. But also, if you're
Upgrade Vue to 3.40:48
returns the result of the method, and now we can get rid of the property entirely. The result is the same. It's a little bit cleaner, which is nice. But also, if you're using a service like Laravel Octane, which keeps the Laravel application alive between requests, it will actually flush out the once cache for you. So you will likely avoid some edge case bugs that come up from using static properties. In any case, I think it's a really nice addition to the framework, and I did want to adjust our code to make use of it wherever possible. So there you go. A nice little Laravel 11 feature for you. Alright, let's move on to Vue. Let's open up our package.json file, and we'll find our Vue dependency, which is currently set to 3.2. I want to bump this to 3.4, so greater than 3.4.0, and then from the command line, we can run npm update and wait for it to go.
Vue dependency, which is currently set to 3.2. I want to bump this to 3.4, so greater than 3.4.0, and then from the command line, we can run npm update and wait for it to go ahead and update all our packages. Of course, you could absolutely instruct npm to only update the Vue dependency here, but by running npm update on all packages, it means you're working with the latest features, and we have version constraints in place so that breaking changes won't be allowed into our application. So I like to run npm update from time to time. You'll want to stop and restart your npm run dev script. I actually have that set up in phpStorm now, so I'll hit the stop button here, hit play, run npm run dev. Of course, if you're using the terminal, you just stop the script, and then you restart it by executing npm run dev again.
Refactor inputs with defineModel2:18
if you're using the terminal, you just stop the script, and then you restart it by executing npm run dev again. Alright, there are actually quite a few changes we can make to our front-end code now that we're on Vue 3.4. Let's start with the text input. I did do a Larabit on this recently, so I'll link that in the description, and you should go ahead and watch that so that you understand the underlying reasons for this. But essentially, Vue 3.4 allows us to improve how we do custom v-model binding in inputs. So say in this text input field, currently we have modelValue, and then we have to define an emit which sends out an event any time our underlying input changes. But now, we can just define a model. So I'll say const model = defineModel() like so. I can now remove the emit and the modelValue prop entirely,
our underlying input changes. But now, we can just define a model. So I'll say const model equals defineModel like so. I can now remove the emit and the model value prop entirely, and then on the underlying input here, rather than binding the value and then listening for the input event, I can just say v-model equals model, and everything else will work as expected. We could do the same for textarea for example. We do the same thing, right? We define an emit, and then we define a model value for our props. So I'll remove that, and I'll set up a model, const model equals defineModel, and then on the textarea down here, rather than all of this work, I can just say v-model equals model. Our custom checkbox is slightly more complicated, and that's because the value of a checkbox in HTML differs from the checked or unchecked status. So we want a v-model to control whether
Checkbox defineModel binding3:41
Our custom checkbox is slightly more complicated, and that's because the value of a checkbox in HTML differs from the checked or unchecked status. So we want a v-model to control whether or not the checkbox is checked, but we can pass in a separate value, which is what will be given to our server in the case that the checkbox is checked. So how do we do that? Well at the moment we have this special event called update:checked, and when we use it in say login.vue, just here, you can see we access through v-model:checked. We have this special proxy that we have set up that emits that event passing in the correct value. So we can use defineModel for this, no problem. Let's go ahead, const model = defineModel, but you have to pass in a string to defineModel, in this case 'checked', and that corresponds to whatever you pass here when making use of the component. So there
define model, but you have to pass in a string to define model, in this case checked, and that corresponds to whatever you pass here when making use of the component. So there we go, that's how we actually support multiple v-models or different v-models inside a component. Now we can get rid of this event. We can also get rid of this checked prop. We leave the value in place, that makes sense, but we can get rid of the proxy, and then instead of saying v-model proxy checked, we'll just pass in the model that we set up at the top of our script here. We still want to pass in this value because we need to support that. I think everything else should work. Alright, let's test it out. So I'm going to log out, and if I go to the login page, here's a remember me checkbox. So first of all, yes, I can go ahead and toggle that on and off, which is great. However, if I set form.remember to
Markdown editor defineModel5:12
and if I go to the login page, here's a remember me checkbox. So first of all, yes, I can go ahead and toggle that on and off, which is great. However, if I set form remember to true, yeah, note that it's now checked, even if I refresh the page. So that is working exactly as I'd expect. We have two-way data binding set up. Great news. The last component I want to add defineModel support to is our custom markdown editor. It's not really any more complex than the other components, but obviously we don't have an underlying HTML input. So let's get rid of modelValue. Let's get rid of the event here and we'll define a model. So const model equals defineModel. And the important thing to note about defineModel is that whatever you assign is basically a ref. So you can use it like a ref. If we come down to onUpdate, for example, see, we're omitting this event
to note about define model is that whatever you assign is basically a ref. So you can use it like a ref. If we come down to on update, for example, see, we're omitting this event and we're passing the value of the markdown. Instead, I can just set the model.value equal to that markdown, and it will do exactly the same thing. We have our watcher here, right? So we're listening to props.model value. I don't need to do that. Instead, I'll just watch the model and then this value will be passed. Everything else should work correctly. In fact, why don't we just test that? So we have our Create view component and here's the body. Let's say hello world. And on our front end, all right, I'm not seeing any content here. How can we debug this? Let's go to markdown editor. Is this being fired? console.log value. Open up our console. It's being fired.
Debug editor watch timing6:35
front end, all right, I'm not seeing any content here. How can we debug this? Let's go to markdown editor. Is this being fired? console.log value. Open up our console. It's being fired. What if we put this under this if statement? Still being fired. What's the value of editor? editor.value. Ah, it's undefined. Okay. I think I know what's going on. If we go into use editor, which is provided by tip tap, yeah, the value isn't set until the unmounted hook fires. So essentially to fix this, all we have to do is make sure that our watch isn't instantiated until the unmounted hook, which we could, of course, do by wrapping it in unmounted like so. So we'll wrap it here, and then obviously I'll just need to close it off at the bottom. And now I can get rid of this console.log, and hopefully there we go. And now it pre fills with whatever content is there before. So there's a little
close it off at the bottom. And now I can get rid of this console.log, and hopefully there we go. And now it pre fills with whatever content is there before. So there's a little bug that slipped through the seams. It happens all the time. Don't worry about it because we spent time refactoring and we actually spent time playing with this feature further. We were able to catch the bug and fix it before it caused any real problems. In fact, as I mentioned a couple of episodes ago, there are a few bugs that have just started to crop up in the application. Let's go ahead and fix them in the next episode.
