This course has been updated! We now recommend you take the Svelte Fundamentals course.
Transcript from the "Events" Lesson
[00:00:00]
>> So as we saw earlier in the course, we can add events to elements with a thing that we call the on directive. And that's basically equivalent to doing element.addEventListener in Vanilla JavaScript. So in this application here, we have a mousemove handler, which is gonna change this value to the current position of the mouse.
[00:00:23] And then we're just displaying that inside the mark up here. Now if we now add a mousemove handler to the div, on:mousemove= and then just pass it a reference, To the function, Then now as we move the mouse around, the text on the screen will change. And you'll notice that this function reference is being called with the event object that you would get if you were using addEventListener, it's exactly the same.
[00:01:03] And we can also declare event handlers inline. We don't need to pass a function reference. We can do it like this instead. Still works, and now we can get rid of that handler because we no longer need it. This can be very convenient at times, but it's also something that you can use to make your templates look like absolute gibberish.
[00:01:38] So generally, once your event handlers get more complicated than this, you want to hoist them into the script block and give them a name. I should point out something here. If you're using an editor where this syntax highlighting causes problems because it's not typical HTML, you can wrap the whole thing in quote marks just so that you don't have those syntax highlighting problems.
[00:02:10] As far as Svelte's concerned, those two things are identical. It's not gonna treat this as a string. So we can also add modifiers to our event handlers. And what modifiers do is they change the behavior of the event handler in some way. For example, we can add a once modifier to this on:click handler.
[00:02:35] Right now, if I do Click me, I'll get an alert. I do Click me again, I'll get another alert. Third time, a third alert. But sometimes you want an event to only happen once. So we'd use the pipe syntax, pipe once. You pipe the event through the once modifier, and now click once, click twice, click three times, nothing happens.
[00:03:00] There's a few different modifiers that we have access to. We have preventDefault, which calls event.preventDefault before handling the event, which is useful for handling form submissions client side, for example. stopPropagation which calls event.stopPropagation, which means that the event doesn't bubble to outer elements. We can add the passive modifier, which will improve scrolling performance on touch and wheel events.
[00:03:26] Although Svelte will, if it's safe to, add that modifier itself. The capture modifier causes the event to be handled on the capture phase as opposed to the bubble phase. Basically what that means is events work their way in from the window when they first happen. So if you click on an element, the window receives the event during the capture phase.
[00:03:50] And then any parent elements get it, all the way down to the element that was actually clicked, which is called the event target. And then it goes to the bubble phase, and it works its way back out again. And by default, Svelte event handlers will be handled in the bubble phase.
[00:04:07] But very occasionally, you will need to handle them in the capture phase, and that modifier allows you to do so. And we also have the self modifier, which only triggers the handler if the event target is the element itself, rather than a child of that element. So that's what DOM events look like.
[00:04:30] But we also have component events, which are a way that components can communicate with each other. So typically, our data will flow into components as props, but it can flow back out of components in cases where it needs to as events. So here in our app.svelte, we have an inner component, and we have an on:message event handler that's gonna alert the details of that message.
[00:05:00] Inside our inner component, we need to set that up so that this event gets dispatched. And the way that we do it is by importing a function called createEventDispatcher from Svelte itself. And once we've done that, we create a dispatch function. And then inside our sayHello function here, we're gonna call dispatch with the name of the event, which in this case is message, and an optional payload of data.
[00:05:51] And now when we click on this button, the inner component creates the event, broadcasts it, and then the outer component is able to handle it. And if we log the event here, Just gonna comment that out. You'll see that what we're using is the native DOM custom event, which, among other things, has this detail property, which corresponds to the payload that we passed to the dispatch function.
[00:06:46] Now a question that we get a lot is why do we need to do this two line stanza where we import createEventDispatcher, and then we create a dispatch function? Wouldn't it be easier if we could just do important dispatch, and Svelte will then get rid of that? So the way that it works is when this script block is being executed when a component is created, Svelte knows which component is currently instantiating.
[00:07:11] And so when we call a function like createEventDispatcher, we're able to create a function that is bound to that specific component. Whereas if we were just importing a function called dispatch, which doesn't exist, from Svelte, then when we called it, Svelte will have no way of knowing which component was dispatching the event.
[00:07:27] And so it wouldn't know which handlers needed to be triggered. So that's why we have this two line stanza, createEventDispatcher. And then this needs to run at the top level of the script block. In the DOM, when an event is triggered on an element, it will bubble out from that element to its parents until it eventually reaches the window.
[00:07:47] That doesn't happen with components. If you want to listen to an event on some nested component, then the intermediate components need to forward the events that you're interested in. So now we have a similar case to before. We have an inner component that is gonna dispatch an event, but it's wrapped in an outer component.
[00:08:06] And the outer component is what's inside the main app.svelte. So what we need to do here is for the event from inner via outer up all the way to app. And one way that we could do that is by going through the whole rigmarole of creating the event dispatcher inside the outer component.
[00:08:35] Do the whole const dispatch = createEventDispatcher, and then we'll create, A forward handler. And just forward the event detail from the inner component up to the app, on:message=[forward]. And now when we click that button, the event is forwarded. But that's an awful lot of boilerplate to do something fairly straightforward.
[00:09:09] So Svelte gives us a slightly easier way to do this. If we just have on:message, just like that, it will do all that behind the scenes. It recognizes that that is you asking the outer component to forward that message from the inner component to its parents. And we can do the same thing with DOM elements.
[00:09:35] So we have a custom button component here with some fancy styling. And we want to get click events handled inside the app. Right now, the button doesn't have an event handler. And again, we could wire up some logic to forward the event manually. But it's a lot easier if we just do on:click.
[00:10:02] And so now, any click events from the button will be forwarded through the custom button component to anything that includes the custom button component, like our app.svelte here.