Why Build Custom Dialogs0:00
Next up on the agenda is custom confirmation dialogs. But before we jump into it, don't forget there is a confirm function you can use, and it'll achieve the exact same end result. This is basically what we're building. And luckily, these days, it looks so much better than it used to. So if you're okay with this, have at it. Save yourself the time and energy. But otherwise, if you want something a little more on-brand, maybe you want to hook up custom handlers for things like this, yeah, you might want something custom. Okay, let's get started.
Creating ConfirmDialog Component0:48
well, I don't want a situation where every time you press the button to show a dialog, an additional fragment of HTML is inserted into the DOM. We kind of want the equivalent of a singleton. So with that in mind, at the bottom of my app.js, I'm going to add it right here, and I'm going to call it confirmDialog. This is basically an extension of the modal that we built in the last episode. Okay, so keep that in mind. Within app.js, I will create and pull this in, confirmDialog, like so. Next, of course, we create it. In my components directory, confirmDialog.vue,
Next, of course, we create it. In my components directory, confirmDialog.view, and I'll use a snippet here. Now, like I said, this is going to itself almost be like an extension of the modal, because if you think about it, that's what a dialog is. It's a modal that has some confirmation and cancellation buttons. That's it. So with that in mind, we can make use of what we built, I believe, in the last episode. So for our footer, we'll have, let's do this, two buttons, one to cancel and one to proceed.
Instead, I just want it to omit an event. So bring up a bullhorn and say, hey, this is the option the user selected. They wanted to proceed or they wanted to cancel. And then someone on the outside can accept that information and respond however they want. So with that in mind, we'll say when you click on this, yeah, we're just going to say handleClick, but I do want some indication for whether they opted out or they wanted to continue. And if you think about it, it's basically a Boolean.
or they wanted to continue. And if you think about it, it's basically a Boolean. false for cancel, true for continue. So click.prevent, handleClick, true. Or what would be a better name than handleClick? selection, I don't know. handleClick, and whether or not they confirmed. So like we said, if we're just going to omit an event, well, we could do it like this to start. Again, I can say clicked or selected, whatever you like,
well, we could do it like this to start. Again, I can say clicked or selected, whatever you like, and then we'll send through the boolean. Did they confirm or did they not? Finally, regardless of their selection, we do want to close the modal. This.modal.hide, and we learned about that in the last episode. Okay, what else? One thing, we do need to give the modal a name, as you may remember, and that's what allows the CSS
One thing, we do need to give the modal a name, as you may remember, and that's what allows the CSS target pseudo class functionality to work. So we are going to call it our dialogue. Okay, so now if I come back to Chrome, we could try this out. Here's our root, here's the temporary variable, and I could say modal.show our new dialogue component, and there we go. We have our defaults.
Adding Dialog Method4:54
and there we go. We have our defaults. But instead, it might be nice to say VM0 modal, and maybe we want a dialog, where I can then say a custom message like that. But at the moment, we get dialog is not a function. All right, let's see if we can make that work. So I'm going to go to the modal component plugin that we built in the last episode, and here's where we install it with Vue.
that we built in the last episode, and here's where we install it with Vue. Now you'll notice I have show and hide. It sounds like we're adding one more here, a specialized one for a dialog. And really, all it's going to do is show the modal with the name of dialog. However, the dialog does accept a message, so we need to pass that through. So now it sounds like when you call show,
so we need to pass that through. So now it sounds like when you call show, you can optionally pass some options or parameters. Okay, so now if we refresh this, it is true. We're not going to get an error anymore. So if I run this again, it will show my dialogue, but we're not populating the message with hello there. It's still the default. Okay, so let's think about this. When I call modal.dialogue, we call show.
Okay, so let's think about this. When I call modal.dialogue, we call show. So that defers here, and all this does is it updates the hash. So how do we send the message we want for the dialogue? How do we send that all the way over here? Because right now it's being hard-coded. Well, to start, this needs to be configurable. So maybe we'll have the params. Let's keep it simple, and then we'll refactor to that.
Passing Message via Events6:19
So maybe we'll have the params. Let's keep it simple, and then we'll refactor to that. We're going to have a message there, and then for our data, we'll accept it here, and this will be areYouSure. Okay, so now at the very least, we have some way to swap out what the message should be. Why don't we emit a basic event? So here, yes, I'm going to update the hash, but yeah, I kind of want to fire an event on the plugin
So here, yes, I'm going to update the hash, but yeah, I kind of want to fire an event on the plugin and include the params that are passed through. And then that way here, maybe even before the component has mounted, I can listen for that event and then fetch the params that are part of the event and assign it to the data object. So that way you fire an event, you let me know what the new dialogue message should be,
So that way you fire an event, you let me know what the new dialogue message should be, we listen for that event, we update this, and then this re-renders. That's kind of what we're doing here. Okay, so let's switch back. If I need to fire an event, how about we add an EventDispatcher to our plugin like this? plugin.events equals a new view instance. And if you're not familiar,
Plugin.events equals a new View instance. And if you're not familiar, if you ever want a basic dispatcher, well, Vue itself is one. It includes those on and emit methods. So that means a new instance of Vue, by its very nature, is an event dispatcher. So it's a good technique to have, even if you want to throw it on the window and you instantly have an event dispatcher ready to go.
even if you want to throw it on the window and you instantly have an event dispatcher ready to go. But instead, I'm going to put it on the plugin. Okay. So now I can say, plugin.events.emit. And what are we doing here? We're showing the modal. And I'll send through the params. Okay, so once again,
And I'll send through the params. Okay, so once again, I just want to make sure we're on the same page. When anywhere in your app you say, this.modal.dialog. Hello there. All right, that's going to hit this method, which will defer to a show method. And this says, update the location hash to dialog, which will toggle that dialog modal we set up.
Okay. So now our confirmation dialog simply needs to import our modal plugin. So we'll say modal from, and let's find it. So we want to go up into the plugins directory, modal, modal plugin. Now that we have it, we'll set this up. Modal.events.
we'll set this up. Modal.events. So again, we're accessing exactly what we set up right here. Modal.events.on. show. All right. Accept the params. And I'll say, just to show you that we're picking up on this. And then I will console.log the params.
And that message is what should now be the dialog's message. Which means all I have to do here is say this.message is params.message. All right. Still a lot to do, but we're getting there. So let's come back and give it one more refresh. Give it another try. And there we go. We now have our custom dialog. So now, think about what we can do here.
We now have our custom dialog. So now, think about what we can do here. Let's say on your app.js or any component, you could have some kind of confirm or on form submit, you know, wherever you want to trigger this. We'll say confirm with a message. And all that's going to do is say this.modal.dialog with the message. Okay. So now if I come back and give this a refresh,
Okay. So now if I come back and give this a refresh, on our root instance, we can now call that confirm method. confirm testing. And there you go. You can do it again. And that still works. But now, there's no easy way to know what happens when you click cancel. And in fact, we're not doing anything.
Returning a Promise Result11:53
this.modal.dialog.then doesn't exist right now. Dialog doesn't even return anything. Okay, so it sounds like if I want to return a promise, then I need to return a promise. And that will accept, resolve, reject. I'll bring this up. And now at the very least, I do have a promise that's being returned. However, let's refresh this.
we need to notify or send some kind of response back noting that we can resolve. Okay, so it sounds like on our confirmed dialog, you select cancel or continue. We call this method. We emit. But maybe instead of emitting directly here, we'll use our modal events instead. Or I'm sorry, modal events.
we'll use our modal.events.emit instead. Or I'm sorry, modal.events.emit. Okay, so now our plugin can pick up on that. Like this. We could say show the modal and then listen for when the user makes a selection. And maybe we should change it to selection because I keep using that word. Clicked is so generic.
because I keep using that word. clicked is so generic. We should change that. But until then, we want to accept whether or not the user confirmed and we'll say caught. And then we'll dump that variable or that argument. All right, are we making sense here? The user clicks a button. We now emit an event for the modal plugin
The user clicks a button. We now emit an event for the modal plugin and we send through whether or not the user confirmed or not. So that means if we did everything correctly, we should see caught after we make a selection. So let's grab that one more time. Activate it. And let's do cancel. All right, and you see false.
And let's do cancel. All right, and you see false. Let's do it again. Continue. And now you see caught. All right, so now that we are picking up on that, I can finally resolve. And we're going to send through again whether or not the user clicked true or false or continue or cancel.
whether or not the user clicked true or false or continue or cancel. Same thing. So this is what we get here. Okay, so now if we did everything correctly, when I call this confirm method, our dialogue will return a promise and once it does resolve, we should have access to that confirmed variable and we should see an alert.
we should have access to that confirmed variable and we should see an alert. All right, fingers crossed. So one more time, we will confirm. I'll click cancel and we get the alert that says cancel. Let's do it again. This time I click continue and we get the alert that says proceed. It works. So now that our basic API is fleshed out,
Building Confirm Button Component14:36
It works. So now that our basic API is fleshed out, here's what I want to do. We have our basic dialogue, but now I want to extend it with another component for a basic confirmation button. This is a button and the only difference between it and a normal button is when you click on it, we display some kind of prompt,
is when you click on it, we display some kind of prompt, some kind of confirmation. Okay, resources.js components confirmButton. We'll paste that in there. And again, like I said, this is effectively a button, but we will accept whatever button text you provide there. Okay, so once again, let's register this and then down here we will add it.
Okay, so once again, let's register this and then down here we will add it. Okay, now I have a new global confirm button I can use anywhere. So if we switch back to our view, let's do our first attempt. So we'll have some kind of form that will submit a POST request to the current page. And now I'm not going to use a button. I'm going to use our new confirm button.
And now I'm not going to use a button. I'm going to use our new confirm button. Like so. All right, let's see what happens. So if I come back and I give this a refresh, sure enough, we do have our new confirm button and you can see it highlighted right there. Okay, so if I submit it, you can see I do have a POST endpoint. Let me show you that real quick.
you can see I do have a route POST endpoint. Let me show you that real quick. It's part of the setup. We just listen for a POST request to that page and we return form submitted. Okay, so our confirm button is working, but it doesn't do anything special at the moment. Let's fix that. First, I'm going to add some classes yet again and what we'll do is just steal these guys here.
First, I'm going to add some classes yet again and what we'll do is just steal these guys here. All right, come back and we have our button. So this represents any kind of form on your site, a registration form, a contact form, a notification form. And when you click it, if you want to prompt the user just to let them confirm, are you really sure you want to cancel your account? Something like that. That's what this is for.
All right, props, accept message here. And it sounds like now when I click on this button, I want to show the confirmation. All right, confirm. And this should be pretty easy at this point because we have our API fleshed out. I can just say show a dialogue with the message that you passed in as a prop. So show a dialogue that says, are you sure you want to cancel your account?
Right now, if they click it again, we'll just prevent the default action. So we can't do that by default. Instead, we're going to do it in a more data-driven way. So we'll accept here whether or not the user has confirmed. And by default, they haven't. Okay, so when they click on this button to confirm, what we'll do at the very top is say, if confirmed is set to true, then we don't need to do anything.
if confirmed is set to true, then we don't need to do anything. Just return. But if they haven't confirmed, we do need to show a dialogue asking them to confirm. And if they do, then we can update confirmed on this instance to true, and then click the button. So when they click it again, click, it calls confirm,
Supporting Configurable Labels21:30
but now the message isn't the only configuration item for the dialog. We also want to tell the dialog what the buttons should be. So I want to set this up in two ways. One usage is you pass a string. For a simple dialog, you don't need to override anything. But another option is maybe to accept an object. And then here, yes, you would include the message, but you would also include the confirm button. And we'll clean this up in a second.
but you would also include the confirm button. And we'll clean this up in a second. But also the cancel button. So let's think what happens now. Call dialog. The dialog method accepts a message, but right now we're calling it message. So let's do this. You could give us a message in params. And then I'm going to do a little normalizing here.
You could give us a message in params. And then I'm going to do a little normalizing here. So we'll say if the message you gave us is a string, then we're going to keep it simple. params.message is message. And then we will pass that through here. Otherwise, if message is not a string, you gave us an object, which means this message parameter is now the object, which is a little confusing.
which means this message parameter is now the object, which is a little confusing. So that's why we're normalizing it. params equals message. If that's confusing, don't worry about it too much. It just allows for a situation where you call dialog with a string or dialog with an object or both. Okay, so now we show our dialog. We emit the event and we pass through that configuration object. The confirmation dialog listens for that event.
We emit the event and we pass through that configuration object. The confirmation dialog listens for that event and accepts the params. And now we don't just have a message, we have made these two buttons, at least their labels, configurable. So I'll do this. To keep it simple, because I have a params object, I just want to do an Object.assign. So we'll store it like this.
And that's what we get. All right, so let's see how we're doing here. Oh, we have an issue. Looks like a missing comma on confirm button. Yep, there it is. Okay, that did compile. So let's give it a shot and see how we're doing. All right, so I am showing the modal or the dialog. Ah, we do have some issues here. Property or method message is not defined on the instance,
Ah, we do have some issues here. Property or method message is not defined on the instance, but is referenced during render. So this is probably because in our dialog, we refactored to this params object, but we're still referencing it like this. So I need to say params. And I guess the same here. You caught that, and I didn't. Okay, so we give it another shot,
So yeah, now think about it. We can respond however we want. It still submits the form. But if you now go back, that can even have its own custom labels. So let's see how we can do this. Okay, this does not need to be there. I'll show you how to do that in our third example. Let's see. Let me go over this. So one thing I see is message,
Let's see. Let me go over this. So one thing I see is message, confirm button, cancel button. That corresponds one-to-one with this. So let's just reference the props directly. And I can access that through _props. I'm just passing through that object. And I think that should be okay. What else? So when we confirm, show the modal.
What else? So when we confirm, show the modal. So here's one thing. We're setting confirm to true. I think that's probably okay. But why don't we just set confirm equal to whatever the user said, whether they selected cancel or continue. And then if they did confirm, we will click the submit button again.
Programmatic Confirm Usage27:08
Option three. Now we're not using a confirm button. We're just calling it programmatically. Are you really sure about this? Cancel, continue. So yeah, now here, this is what I was going to show you. Here we could say, if confirmed, alert, proceed, do whatever.
if confirmed, alert, proceed, do whatever. Otherwise, you didn't confirm. So we'll say, alert canceled. Or let's show another dialog that says, okay, canceled. This is what I meant to show you. Okay, so there's our alert. But if we give it another shot and we cancel,
Got it. Okay, so let's give that one another shot. Cancel. And now notice we updated the button there. Okay, so I'm going to give you a little bit of homework. We're running high on time. I will upload this code to GitHub. The next step would be, in a situation like this, you may not always want two buttons.
