3.4 Improving Decorated Components
The main problem with decorated components is the prop and event setup. It's annoying. In this lesson, you'll learn how to simplify prop and event setup down the component chain.
1.Introduction1 lesson, 01:47
2.Advanced Basics2 lessons, 23:38
3.Customizing and Extending Components4 lessons, 34:53
4.Just Plain Cool Stuff3 lessons, 29:49
5.Conclusion1 lesson, 00:57
3.4 Improving Decorated Components
We have a working confirmation modal and it needs some work. It needs a lot of work actually, but we're only going to focus on two things. The first is how the OK button looks because we want to be able to change the color as well as the text so that it better fits the content of the modal. And then we also want to discuss the props, because we are essentially replaying a lot of the same props, of course, we need to specify the show and the hide event listeners for the confirm-modal. But inside of that actual component, we are essentially just replaying those things and it would be nice if we could automate that in some way. Let's first of all talk about configuring our OK button and then we will focus on the props. So lets start with text. The text of our button could be changed in a couple of different ways. We could have a prop called confirm-button-text and then we can set that to wherever value. And that would be fine, but I think that that's not the best approach. First of all, because if we use a slot, then we have a more declarative syntax in my opinion and it also gives us more flexibility because we can use more than just text. We could use HTML, which means that we can use an icon like from Font Awesome or things like that. So let's not use a prop in this case instead we will have a slot. So let's go ahead and setup the template it's going to have a name of confirm-button-text and then we would have our text there. So let's go ahead and implement that slot right where we have that OK. So of course the name is going to be that-confirm-button-text. And we could go ahead and give it a default value of OK, I mean, I think that that would be perfectly acceptable. And so now whenever we view our modal, we are going to see, not what I expected to see. So let's do a hard [LAUGH] refresh and yeah, okay, so what's going on? We have our slot name "confirm-button-text" that's okay, and then our template name, we need that to be slot. Yeah, that's kind of important there. So now that should update and we see delete great. So we could probably do the same thing for the cancel because we might want a confirm that says yes and no things like that. So let's just go ahead and replicate the same thing for the cancel, of course the name is going to be "cancel-button-text" and we will make the default Cancel. We're not going to change any of that text actually inside of our app component, so we'll just leave that alone, but that at least gives us the ability to change the text. Now as far as the coloring is concerned, well, we are using bootstraps built in classes to style our button, and I've gone back and forth on this because my thought is If we stick to just bootstrap classes, then we're bound to bootstrap. But I mean, really, we're bound to bootstrap anyway with everything else that we've been using. So if we were ever going to change our CSS framework, then we would have to change everything anyway. So what we're going to do then is actually have a prop so that we will pass in the CSS class that we want to use, so in this case, it would be confirm-button-class. And for this, we would want the "btn-danger" class because to me that would be representative of trying to delete something. So we're going to pass this prop confirm-button-class and then we will use that. So let's first of all add this to our confirm modal and of course we need to change this so that it is camel cased. But then what we will do is instead of saying button and then button primary, we will still have our HTML class attribute set to button,. But then we will v-bind class and we will use either the confirmButtonClass, if it was provided, or we will also have the default, which is 'btn-primary'. So now we should be able to see a danger colored Delete button and we do and if we click it, Resource deleted, great. And of course, let's prove that if we remove the confirm-button-class prop then we're going to have a blue button, and we do. All right so we have successfully made our confirm button configurable. But deleting a resource is fairly common and so we would want to use this particular modal in a variety of different places throughout our application. So it kind of makes sense to create a component for displaying a delete modal, so, let's create a new file and let's call it Deletemodal.view. Now, we're going to start with the code from app because that has a lot of the code that we want it to start with, I mean, after all, we are using the confirm-modal here. So let's copy that, let's paste it in, and let's make a few changes to the template, like we don't need the div element or the button for showing the modal, so we can get rid of that so that all we have is our confirm-modal inside of our template. And the script, we don't need the name, we don't need the data, we don't need the methods, I don't think. But we do need a prop for 'show' because we have essentially replayed the show prop in everything else that we've done in the ConfirmModel so that we can then set the show prop for the generic modal. So once again we're going to have to replay a lot of things, but as far as everything else we do need to setup a title template, so we could copy that from our confirm-modal as well as just the default slot and use that there, and that should be fine. However, we are going to run into the same issue that we did in the previous lesson, we need to change this modalShown to 'show', we need to replay once again the 'hide' event so we will emit that. Now we do need to do the same thing for the confirm event because we are listening for a confirm event on the confirm modal so that we can replay that and yeah that should be it as far as replaying is concerned. We don't need the style so let's get rid of that. Now as far as the app is concerned we no longer are going to use the confirm-modal we will use the delete, so let's just make the changes so that we can use that new component. So DeleteModel, DeleteModal, DeleteModal and we still need show, we need hide, we need confirm, we do not need to specify the confirm-button-class, we do not need to set the template for the 'confirm-button-text' but everything else we will have. Okay, so let's click, we see it works, if we click Delete, we see our Resource deleted alert box. Let's do a hard refresh to make sure that that wasn't cached. Okay so we have created a new component for a Delete-modal, however, you can start to see the problem with our props. We are replaying everything and especially with the events for ever new event that we create, we're going to have replay that down the road. So this can get a little unwieldy and there's gotta be a better way and there is we have two directives that we can use. The first is v-on and we can pass the $listeners to v-on, so basically it works like this. Whenever we use the Delete-model, we are setting up event listeners for the hide and the confirm events. So as far as our view object is concerned, we have this $listeners property and those two listeners are being passed and they are contained in this $listeners. So whenever we say v-on we are essentially saying on every event listed in our listeners setup the listener for it. So that's automatically being passed down to our confirm-modal and we could do the same thing inside of our ConfirmModal. So we would no longer have to setup the hide event, in this case we are replaying the 'hide' event, all we have to do is just, okay, take the listeners coming in, set them up, we're golden. And we can do the same thing for the props as well, and for that we simply use v-bind and then we pass in the attributes. So in this case everything that we are passing to our Delete-modal the show prop which, well, that's it the show [LAUGH] prop is going to automatically be setup here. It's binding the show prop and setting that up, so we no longer have to do that explicitly here. That also means that we don't need our props or at least our show prop for our Delete-modal, so we can get rid of that completely. We can also get rid of these events, because we don't need those anymore. Now we do need this prop for the confirm-button-class because we are explicitly setting that for our confirm button but that's it. Any prop that we pass down is going to automatically be bound using the v-bind. All of the events that we are passing down will automatically be setup. So then, inside of our ConfirmModal, we will essentially do the same thing we will say v-bind and then we will set that to the attributes that are being passed down. We can get rid of the show setup but here we want the backdrop set specifically to static because once again we are in ConfirmModal, we want that static backdrop, so we will pass that on. But since we no longer need that 'show prop', we can get rid of that so that now all we have is our confirmButtonClass. And then we don't have to do anything inside of modal because that's going to receive everything there, so I think we are good to go to try this out. If we click on Show Modal, well, let's do a hard refresh. Let's click on Show Modal, we see our modal display. If we click on the Delete button, once again, we see our Resource deleted alert box. Now if you wanted to be absolutely sure you can pull up the Vue inspector, we can look at our components, let's go to App. If we look at the props, we have modalShown, so if we Show our model that changes to true, if we look at the DeleteModal, now we don't have any reactive state now so there's nothing to inspect there. The ConfirmModal, we have our btn-danger set for confirmButtonClass everything's fine there. As far as the modal component itself, the backdrop is set to static and then the show is true. If we click on Cancel, that's false, if we look at the App, then modalShown is false. So everything is working as it should we're just not having to replay those props and those events over, and over, and over again. All we have to do is v-on our listeners, v-bind our attributes, and everything else will get set up. So now we have a confirmation modal that is configurable and it's much easier to implement.