Intermediate Vue

Transparent Components

Ben Hong
Pandan Studio
Intermediate Vue

Lesson Description

The "Transparent Components" Lesson is part of the full, Intermediate Vue course featured in this preview video. Here's what you'd learn in this lesson:

Ben introduces transparent components, showing how to build reusable form inputs with v-model support. He also introduces a helper function called `defineModel` to streamline the process of setting up v-model bindings.

Preview
Close

Transcript from the "Transparent Components" Lesson

[00:00:00]
>> Ben Hong: Next thing we wanna talk about is transparent components. And so this is where this is going to become actually rather critical. We're going to take a look at our code base, and one of the things you'll notice here is that if you take a look at, say, like, the input field, this is another common one where, let's face it, forms are about like, what, 95% of our bread and butter as web developers.

[00:00:18]
And so, it would make sense for us to basically take this form control that we have here, where we have a typical task input of text, and then basically wrap it in a component that can then be reused, right? Because then our styles and stuff can propagate and we don't have to deal with all this all the time.

[00:00:34]
So your first instinct when you're thinking of this is like, all right, cool, we're going to go ahead, let's create a base text input. That's what we're going to do. All right, so we'll take this bit here, this whole title, and we're going to go ahead. And so I'm going to go ahead and queue up the single file components.

[00:00:52]
It did not install sass, so that won't be applicable. And we'll drop it in here, okay? First thing first, so let's go ahead and don't. Let's ignore this. Let's not worry about the V model for now. This is good. We've got a placeholder. We have disabled. Okay, setting and whether it's required or not.

[00:01:10]
Okay, so typically when we're designing components, your first instinct might be to define props for every single one of these. But this is, that would be a lot. Right, because then you're basically just kind of recreating the DOM API. And so what we really need is to think about what we want to do as far as, like, okay, we want to configure specific things that we're going to use within this base text input.

[00:01:32]
So let's start with some of the obvious ones. So the first one is we're going to want to always give it a label. So that'll be type string. Wait, yeah, I did that right. Required, true. And so we know that here, for example, we can say, okay, the label will go here.

[00:01:47]
Then here we have this thing where we also need to pair the for attribute with the id. So usually I find this actually just easier to just call it id. And then this way we'll just use it to populate both. So then type string require true. And then we can just populate here and here.

[00:02:08]
Okay, so that's good. Whether it's disabled or not, that is something that you would think that you want to define, but honestly, this is actually something we would want to be able to just pass through, because this is part of the native input and so not something you necessarily want to configure.

[00:02:22]
And whether it's required or not, that you also think, yeah, that should be something that should just be passed through as well. And so then you're also probably thinking, okay, well, then, yeah, actually, in fact, what I really want is for most of the attributes that view passes to go to this input element.

[00:02:36]
Because really, this is the whole purpose of us creating this reusable piece. Right. The label is really not what's being customized. Neither is this form control that we're wrapping around. So the question is, how do we do that using what we just learned about? What we could do?

[00:02:49]
You're probably thinking is, well, couldn't we do this? V-bind equals. And then if you didn't know this, we have this thing called $adders, which stands for attributes. What Vue does, essentially, is take all the attributes that you pass this custom component and then sends it to whatever element that you wanted to.

[00:03:05]
Basically, you're assigning it to. So when you do this, let's go ahead and actually bring this up. So, what I'm gonna do, I'm gonna, how do I wanna do this? Okay, we're going to go ahead and we're going to create a quick view. Real quick. I'm going to call this Sandbox, Sandbox page view.

[00:03:21]
And this page is just going to serve as, like, something separate from the application code. And that way we can just basically queue it up and see different demos without interrupting the rest of it. So I'm going to go ahead and update that real quick. We'll drop this all the way here on the bottom.

[00:03:38]
So, this will be sandbox, and then this will be the Sandbox page. Okay, see the arcs to the right. So we open this up. Okay. Yep, it's empty right now. So that makes sense. Let me go ahead and fire that up. Sandbox page. There we go. All right, we see our Sandbox page.

[00:04:05]
All right, so what I'm going to want to do now is let's go ahead and import that base text input that we just created. The base text input is created, and then we're going to go ahead and bring it on, and we're going to do. We're gonna add a placeholder and we're gonna call it my test placeholder.

[00:04:24]
And then. Yes, partial holder, business not assignable. That's fine. Okay, so we save that and then you'll see. Here we go. Here's my text being bound. And what you notice here is that this placeholder is being passed correctly accordingly into the input in this particular case. But something that should be kept in mind, though, is that especially when you have different routes.

[00:04:49]
So it's kind of funny that it's working in this particular case, but what I wanted to demo is the fact that you do sometimes find that, especially with the single root nodes, what VUE typically does, again, it's kind of interesting, the behavior is happening here is that it'll actually send your attributes to the root node, because that's what VUE knows, right?

[00:05:09]
Whereas if you think about it another way, if we had multiple nodes here, VUE has a hard time determining where to send something to. So typically what we want to do is when we're binding the adders is you have to do something called basically to disable the inherit attributes.

[00:05:25]
There's this macro inside of the script setup for view that's called Define options for those who come from the Vue. Two days, you might recognize it as basically that it would look like this. Instead, you say inheritAttrs, false. So, we basically created a macro to make this easier to do, so that you didn't have to have a script block and a script setup block.

[00:05:50]
And so this whole thing can then be put inside of here and just like that. And so this is typically what you'll see in these sort of transparent components where you want to make sure where the attributes are being applied to. And so the reason why we have props here is because if you don't have these props already defined, VUE is just going to send everything along like in the bundle of attributes.

[00:06:15]
But since you have these props defined for ID and label, that's what allows you to designate it to other parts of the component besides just the input. So the thing with this, though, is that while we have. Basically we have this here, if we go ahead and let's go back to our sandbox page and let's go ahead and create a ref from view.

[00:06:39]
And this time I'm gonna call it const. Firstname equals ref empty and we're gonna v-model this to first name, okay? And then let's wrap this in main and then we'll go ahead and render out whatever it is where we think first name should be. You'll notice that nothing's happening.

[00:07:04]
And so it's probably like, that's weird. That's not what I expected because, right, we put v-model on text inputs all the time, right? I mean, it's right here we did V model to the thing and then it just talks to the thing. And so the reason for that is because when you're working with transparent components and you want to do something like a V model, you actually have to be very explicit about what it is you're trying to do, similar to what we were talking about earlier.

[00:07:28]
So for the base text input perspective, the way you would typically do this, and I want to demonstrate this the long way first, so you understand what's happening here is that you basically define what it is that you want to bind it to, because what V model ultimately is when we take a look at it.

[00:07:43]
So let me go back, let me close this and then go to sandbox page. What you're really trying to say here is that you want the value that's bound to the text input to be first name. And what you also want to do is when it's on on input, you want it to go ahead and then basically say like, first name equals event target value.

[00:08:08]
That's like the long form of what you're trying to do. And so typically the way you'd have to accomplish this is you'd have to come in here, you say, okay, well what we're going to do then is we're going to say, okay, so there's going to be a.

[00:08:21]
Let's see, we're going to have a first in this case. So it's called model value. This is the prop that's actually bound to v-model by default. And so then we can say type string and then we'll say default like this. And then you would also then have to define the emits to then say, okay, we're going to update.

[00:08:43]
Then what are we updating? We're updating model value. And then from here you could then say V model equals model value. Just like that. And so all that, if we did this correctly, V model model cannot be used on a prop local binding.
>> Speaker 2: You don't have the V model on your using your component.

[00:09:12]
>> Ben Hong: You're saying this one. This should be the V model, right? Yeah, you're right.
>> Speaker 3: It's because the ID is required.
>> Ben Hong: I think you might be right. Yes, correct. That's one of them. And then what else do we require? We required ID and then we have a label.

[00:09:34]
We don't have a label. Yes, this is when the linter is doing its job [LAUGH]. First name, okay, fantastic. Great. Okay, so that's rendering correctly now. And so, the v-model to the first name. This one is where it's currently not responding the way I would expect it to.

[00:10:00]
And even though we have this already bound, which is so fascinating. Okay, I don't wanna do this.
>> Speaker 4: Does there have to be something to listen to the emit.
>> Ben Hong: That's what's supposed to be. Okay, so typically this is what it's supposed to be because you're supposed to essentially be saying props model value.

[00:10:25]
And here is where we would say on input, we would say emit. And then we would say update model value. And then event target value is what it should be saying. And then. So, I need to, where's the emits here? Const Emits, assign it. And then like that.

[00:10:49]
And then it's still, possibly null. That's fine. You can yell at me all you want. Okay, so I'm not sure. There you go. Now we have it working. Thanks for calling it out. That's right. We have to do it the long way first because so you can see this is prone to lots of errors, if that demonstrates anything else.

[00:11:07]
And so over time, the team basically realized that this is something we do a lot. And so instead, this is too much boilerplate. What we can do is instead we have this new helper function called usemodel. And so what usemodel does is all this boilerplate we just basically worked through.

[00:11:23]
So in that case we would say, in this case, text value equals. Yep, equals use model or define model is what I meant to say. And then you can, if you want, you can pass it what exactly it'll be. So in this case, we know it's going to be a string.

[00:11:38]
And then this is where we're gonna go ahead and then say, yes. Okay, now that we have this, we don't need all this boilerplate and we do V model on the text value like this. And then it's still works. So, I can delete that, and I can delete this.

[00:12:06]
And so, boom, we have this. What's nice about this particular V model approach though, is that you can actually then start to expand upon it. Whereas before we had model value, you can actually start passing arguments as well to your V model. The way that would look is that we basically have the ability to then say, okay, well, inside of my base text input, let's say we had two text inputs that we want, the first name and last name.

[00:12:34]
So, in this particular case we're gonna ignore this for now. As far as v-bind adders, you can actually then pass it an argument to basically then say whether it's the first name or not. So the way that would work is you would say define model and you would say, this is my first name.

[00:12:50]
So, let's see, let's make this clearer. So that's easier to tell. Const Last name, define model string. And this is the last name. And then what we can do here is great. We can go ahead and then say first name here, and then we're going to bind it to here.

[00:13:15]
And then inside of our sandbox view. Then we can actually now say first name is bound to this particular V model inside of the form. And then v-model to. And then in this case, last name. You can actually bind directly to it this way, like that. And then, voila, we should have Smith Ranny.

[00:13:48]
And there you go. So the define model just makes it way easier, especially with this. I mean, you could do it before, but it's just a lot more convoluted. And so, the syntax makes it very clean as far as making it. You can start composing your forms together in some pretty interesting ways because you can bind the V model to different form inputs.

[00:14:06]
You can be very creative as far as how that goes.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Start a 5-Day Free Trial