Decoupling Event Handling0:03
In the previous episode, we implemented our own little event system so that we could execute our own code when an event occurs. It's not really an event, it, it's really just a callback, but the idea is logically the same. But I don't necessarily like this implementation. I mean, yes it works. Yes, we implemented, but we are coupling this handler with this game object.
but we are coupling this handler with this gameObject. And I don't necessarily like that. It's not that big of a deal in this case because we only have one gameObject. But still I like the idea of just a normal event to where we set up an event listener for a particular event. In this case it's global. We are listening for this event at the document level. And even though yes, we check what element received
We are listening for this event at the document level. And even though yes, we check what element received that event, it is still decoupled. I want that. So instead of using this addEventListener method, I essentially want to do this. So that's, we'll just get rid of those. So all that time in the previous episode is wasted. It's not wasted. Um, it was some good content whatever.
Dispatching GameOver Event1:13
It's not wasted. Um, it was some good content whatever. So let's say that we would have an event called GameOver, in which case we would execute, you know, a function that will essentially do the same thing. It will show the feedback and it will then set the appropriate UI changes. And that works just fine and, and we can actually implement this because we have the ability to emit our own events.
and we can actually implement this because we have the ability to emit our own events. And this was a long time coming, it took forever to get this functionality and I don't necessarily know why because it was asked for a lot and you know, there were a lot of systems that we had to custom build ourselves. It's not that big of a deal anymore because it is built in. All we have to do is dispatch an event and then we create a new event object.
All we have to do is dispatch an event and then we create a new event object and then we give it a name. So GameOver in this particular case and that's it. So that for every listener that is set up for the GameOver event, it's going to execute. Whenever we dispatch this event, that means that we can get rid of this addOnEnd method, which also means we can get rid of the private field that we created and inside
which also means we can get rid of the private field that we created and inside of the browser everything is gonna work just fine. Let's play a hard game so that we can go through all of the attempts and voila, we see the same exact functionality that we had before but now we are actually emitting an event. But we can improve upon this because you know, instead of just saying game over, I would also like to include the secret number.
Adding Custom Event Details2:56
because you know, instead of just saying game over, I would also like to include the secret number because if I fail at picking the correct number, I want to know what it is, which means that whenever we emit, or I guess I should use the term dispatch, whenever we dispatch our game over event, we need to supply some information about that event. Just like within a normal event handler, we can see what elements received the event and in the case of a key down, you know,
what elements received the event and in the case of a key down, you know, we could see the keys that were pressed because there's always information about the event that took place. So this means whenever we dispatch our gameOver event, we don't want to dispatch just a normal event. We want to dispatch a custom event because then we can include an object that contains information about the event.
because then we can include an object that contains information about the event. Now there's a little bit of difference with this particular event object because we have to have a property called detail. It would be really nice if we could just build an object that has the data that we need and then that would be it. That would be perfect. But that's not the case for a custom event. Our own event object has to have a detail property.
for a custom event. Our own event object has to have a detail property and that is an object that will then contain all of the information that we want to include. So here we would include the secretNumber, but I wanna do this, you know, our secretNumber is currently private. I want to make this a private field. So before we finish that, let's go ahead and let's define secretNumber as private.
So before we finish that, let's go ahead and let's define secretNumber as private and then we will change every place that we use secretNumber, which we don't use it in very many places. I mean it's primarily inside of the checkGuess method. So here, if the guess is equal to the secretNumber, then we will dispatch our custom event of gameOver. We will include the detail of the secretNumber and that's going to work just fine. But then we also need to use the private secretNumber.
and that's going to work just fine. But then we also need to use the private secretNumber field there. So now we can go back to our own eventListener, which is somewhere around here if we scroll for days, there we go. So where we are adding an eventListener for gameOver, now we have an event object and we can get the secretNumber from the detail. So we'll just get that property.
and we can get the secret number from the detail. So we'll just get that property. So our showFeedback will still say "Game over," but we also want to say that the secret number is, and then we would include the secretNumber so that we can go back to the game and let's play it. We'll just make it a hard game because we can end that quickly and sure enough we can see
Emitting Guess Events5:50
because we can end that quickly and sure enough we can see that now the secret number is included. So now there's no question as to you know, why we failed. We know what the secret number is. But you know, I also want to do something when we make a guess because whenever we make a guess, okay, whenever we make a guess, I mean it's nice that yes we, we update the history,
whenever we make a guess, I mean it's nice that yes we, we update the history, but I also want to display the amount of attempts that are left. And since we are essentially doing this whenever an event occurs whenever we make or check a guess, it kind of makes sense to go ahead and define a guess event. So we would add an event listener for game, let's just call it guess.
So we would add an event listener for game, let's just call it guess. And this is also going to include some data. So we will need access to that event object, but we need to go to the checkGuess method and really we need to change this because if we are going to emit both the gameOver event as well as a guess event, then we need to make this a little bit easier to manage. The first thing I wanna do is put this all on one if
to make this a little bit easier to manage. The first thing I wanna do is put this all on one if statement, so that if we don't allow duplicates and if we do have a duplicate, then we will simply return there. But then I want to create some constants here. So we'll have an isCorrect, which we will basically check if the guess is equal to the secretNumber. Let's also have isLastAttempt
equal to the secret number. Let's also have isLastAttempt because that way we know that the game is also over because the game will be over if we get or guess the correct secret number or if it is the last attempt. So let's just take this right here to where we check the maxAttempts and see if it is equal to the history length. So that's now this will change to where if it is correct
and see if it is equal to the history length. So that's now this will change to where if it is correct or if it is last attempt, then we will dispatch the gameOver. But before we do that, we also want to dispatch the guest event. So we will call dispatchEvent. We want this as a new custom event that has the name of gameGuess. And then we will have our event object.
of game guess. And then we will have our event object that has a detail property and what do we want? Uh, we don't necessarily need to know if it is correct or if it is the last attempt, but we do need to know the result of this. So you know, down here to where we return the result, we can get away from that completely so that all of this information will, will be done here inside of this event.
of this information will, will be done here inside of this event. So let's do this. We will also have our result here so that if it is correct, well then our result is simply correct. However, if it's not, then we will need to check. If the guess is less than the secretNumber, well then we want the result to be too low, otherwise it will be too high so
well then we want the result to be tooLow, otherwise it will be tooHigh so that then we can include the result here. We could also include the guess and really we could include anything that we might need. But the only other thing I think is uh, the remaining attempts. So here we can get that very easily by getting the maxAttempts minus the history.length.
getting the max attempts minus the history length. So there we go. Now we will emit this gameGuess event, which means let's see, where do we do that? Uh, right not here. Where do we check the guests? Right here is where we check the guests. So we get the guests, we validate the information, then we get the result, but now we don't need to get the result because that's going to be handled inside.
but now we don't need to get the result because that's going to be handled inside of the event handler for the guest event. So now we just need to update the history. We need to reset the guess which we need to do that here, or we could do that inside of the event handler. Um, I'm open to either, but for right now, we're just gonna do this so that we need the guess, we need the result, but we have multiple pieces of information.
that we need the guess, we need the result, but we have multiple pieces of information that we need from the event details. So we could do something like this where we will get the guess, we'll get the results, but we also want the remainingAttempts and all of those are coming from the detail property. So we're just going to destructure that object so that we have access to those things easily. And here we could show the feedback of
that we have access to those things easily. And here we could show the feedback of you have and then we would include the remaining attempts. Remaining attempts. It's kind of repetitive there at least from the code aspect. But there we go. If we take a look at our game now, if we play the game every time we make a guess, we can see that we have the remaining attempts and eventually we are going to get there.
Event-Driven Architecture Discussion11:12
that we have the remaining attempts and eventually we are going to get there. Yes we do. We also see the secret numbers eight, but let's play a hard game. And once again we see that we have four remaining attempts, we get the feedback that we need and then whenever the game is over, we see the secret number. Now this starts to lead us down the rabbit hole of event driven development, which I'm not going to say is the way that we should go
of event driven development, which I'm not going to say is the way that we should go because it does add a little bit of complexity. It certainly adds a lot more code, but it does give us the opportunity to essentially abstract away all of the native DOM stuff so that at the end of the day what we are dealing with is just a set of events that happen from either the game or happen from the ui. Like for example, here is the click event listener for
that happen from either the game or happen from the ui. Like for example, here is the click event listener for whenever we check if we are submitting a guest or if we are ending the game. Well, from a code standpoint, I mean yes this code works, we can read it and we can see what is going on. But we could arguably say that we can make this cleaner by doing something like this to where we would dispatch an event, it would be a custom event and we could call it uh, UISubmitsGuess
where we would dispatch an event, it would be a custom event and we could call it UI submits guess for the lack of a better name. And then we would have the detail which would have a guest property, which would come from the ui.getGuess(). And you know, I can't think of anything else that we might need. But then inside of this event handler that deals with the nitty gritty DOM stuff, we can take out all of this that really doesn't do anything with the DOM so
with the nitty gritty DOM stuff, we can take out all of this that really doesn't do anything with the DOM so that then we could have our own event listener for the UI submit game event to where we would have our handler and we would get the guests from the event details. And you know, this also depends upon the game, which I don't necessarily like being global, but for right now it is what it is. But this also gives us the opportunity to dispatch another event for whenever we end the game.
But this also gives us the opportunity to dispatch another event for whenever we end the game. So if we dispatch, and in this case it could be just a normal event, which we will call endGame, and then we would have an event listener for that event so that then we could essentially hide the DOM stuff completely. Uh, what was this? This was endGame. Then we would have our callback,
Uh, what was this? This was end game. Then we would have our callback, which would then disable the settings UI so that we could take this click event listener. We can just define that inside of our immediately invoked function. That way it's not public, it's not accessible and, and there's really no need for that to be outside. So that as we start to break these things up into individual files
So that as we start to break these things up into individual files and individual modules, we aren't dealing with the raw DOM elements in the the raw DOM objects. We are working with the higher level of the game or the UI. It's just a different way of looking at the application and implementing it. You know, because once again, I'm not gonna say that this is the best approach because it certainly does require a lot of extra code,
that this is the best approach because it certainly does require a lot of extra code, it does add extra complexity. But when the application is nothing but a set of event listeners and we're not having to deal with DOM objects, we're dealing with the API that we built ourselves, while things become a little bit easier to read and maintain as well as scale. So it's an option that's available.
and maintain as well as scale. So it's an option that's available. I'm not gonna say that it's an option that you should do because there are certainly drawbacks to it, but the option is there and if you want to go down that rabbit hole, you certainly can.
