♪ [music] ♪
In this exercise, we're going to make this
really sweet JavaScript Drum Kit. I'm not really exactly sure what it is but it's
really fun to play and when you hit the corresponding key on your keyboard,
it's going to do two things. First of all, it's going to play the sound that's
associated with that key and second of all, it's going to do this short little
animation where it pops the button up to be a little bit bigger than we want.
And then also, it will apply that yellow border and that little background there.
It's really, really subtle and I'll show you how that's working here.
We inspect on this kick one right here. You see we have this data dash key and
we'll look that in just a second, but when I press it, you can't even see it adding
because it's going so quickly. But what that's doing is it's adding a class of
playing to that element which will then kick in the CSS if I open up today's
exercise and we'll look at stalled at CSS. You see we have class of playing that's
going to scale it up by 1.1 in our CSS. It's going to change the border color.
It's going to change the back shadow. Now because if we look at our regular key
here, you see that we have a transition that is 0.07 seconds long really,
really quick. And that's going to scale it up and change the background color behind
it. So that's really the two things that we have here and if you would like to sort
of go at this on your own, pause the video here, try to get this up in working.
Otherwise, let's go ahead for the ride and take a look at what we're working with
here. So we've got a div with class of keys and inside of that,
we've got a whole bunch of divs with a class of key. Now, each of these keys here
obviously has like the clap, what sound it's going to make as well as the key that
you should hit on your keyboard. But the important thing here is that every key on
your keyboard when you press the up or the down, when you key up or key down event,
there is going to be something called the key code that is associated with that key.
Now, I've got a little website here I whipped up a couple of years ago because I
always find myself searching for it and it's called keycode.info and when you
press a key on your keyboard like escape or space or A, it's going to have number
associated with that specific key on your keyboard and this is the most consistent
way that I found across browser, cross languages. It's not absolutely perfect
but it gets you most of the way for most of your standard keys. When you click
or when you hit 65 like when you key up and we're going to check if that was the A
key then we're going to play the corresponding audio element that also has
the data-key. Now, what is this data dash key? If you've never used a data
attributes before, this is not a standard. You won't find this Googling anything,
anywhere you want. And essentially, data attributes were brought about in HTML when
people were just making up their own attributes. We have things like source and
class, and those are standards. And then people just started making up their own
and the people who made HTML were like, "whoa, whoa, whoa, chill out,
you can't just start adding shit like for whatever you want." So we came up with
this idea of data attributes where if you want to make up something like a key,
you have to put it behind a data-something So what I'm doing here is I'm
using data attributes to hook up this, the data key 65 along with the data key audio.
So that when someone hits the key on their keyboard, we're going to find the audio
element and play it and we're going to find the key div and we're going to add a
class of playing so it will animate itself on in. So let's get started,
go over to our script tag here and the first thing we need to do is just be
focused on listening for a key up event. Now, the way that we do that is you first
get whatever element that you're listening for and in our case,
I'm going to listen on the window. Sometimes, you might want to listen on the
input or a div or a text area or something like that. And we're going to add an event
listener. The event that we're listening here is called key down.
And then next, we have a function which will give us the event and inside of that,
we have nothing. And then I'm going to get rid of the rest of this stuff here.
So we're going to listen for the key down event and when that happens,
we're going to run this function which will give us the event and I'm just going
to console log that event. Open up my console, now whenever I press one of these
keys on the keyboard, you'll see that we get this keyboard event, that's what E is.
The event is just the object full of data describing what happened and it'll tell us
all kinds of info like what key was actually hit. But the thing we're
concerned with here the key code, which is the number that is associated with that
key, and that's essentially what all this website is. When someone hits the key up,
we're just going to display the corresponding number that you have.
So we go down here, we can log e.keyCode and see what we've got.
Good, now we've got all these different... If you hit spacebar, you can get 32.
If you hit escape, you're going to get 27. Now what we need to do is say,
"is there an audio element on the page that has a data dash key of 65?" And we're
going to use document.querySelector because we're only looking for one.
If I was looking for many, I would say query selector all but in our case it's
just query selector. And we're going to listen for an audio, we're going to try to
select an audio element but we want to select it where it has a data - key,
like there's no class on here. And sometimes I see people say like,
"class=key-65" and they'll split it and select something with a class of key 65.
That's a bit messy to me. I'd rather just use its own data attribute here.
So we can use and attribute selector if you've ever used this in CSS,
works the same in JavaScript. Attribute selector say something like this,
"data-key=" and normally would say 65, right? But that is going to be a variable
that lives inside of this event. So what I'm going to do is I'm going to switch
these to back text and we're going to use ES6 template strings which is dollar sign
curly brackets say "e.keyCode." Now, we can console log audio and see if we have
selected an actual audio element. So I'm going to refresh, I'm going to hit my A
button. No, we got an error, audio(data-key=65) is not a valid
selector. What did we do here? I think we need to pop a set of quotes around this
actual key here. Let's see if that works for us. Hit A. There we go.
So it looks like you do need quotes around your actual number here. Now when I hit
the key, and hit S, I'm going to hit D. You see that we are getting the
corresponding audio element for that specific key. Now sometimes we're going to
hit, I'm going ahead and hit Q. We get null. Why do we get null?
That's because there is no audio element associated with 81. So right away,
right there we can do is we can say if there is no audio, if bang audio,
then we are just going to return. And that would just stop the function from running
altogether. Okay, good, and that would just stop it. Now what we can do since we
have this audio element, we can play it. Let's try that. S, D, F.
Now it kind of works but here, hit F over and over again, F, F, F, F.
I'm hitting it multiple times, but it really only plays once every so often.
And that's because the open hat F, it plays and it takes like maybe two or three
seconds to actually get to the end. And if you call .play on an audio element
that is already playing, it won't play it again because it's like,
"oh, why would I do that? I'm clearly already playing with that." So what we
want to do before we do that is sort of rewind it to the start of the element so
that if you hit it in succession over and over again and over again,
it will just rewind it to the start. So let's say "audio.currenTime=0." Now this
is going to rewind to the start. And now if I just hammer on F,
you see we get it over and over again, AAAA, SSS, DDD, FFF.
Good, playing over and over again. I'm going to try some of the other keys on the
keyboard, nothing happens because we're doing this check if there's no audio
element. Now, what we also need to do is select the corresponding key that is with
it because we want to add that little animation that we have here.
So let's say "const key=" and I going to take this entire thing and switch it out
with a dot key. So instead of selecting an audio element with the data dash key,
we could select a div or in our case, something with the class of key but also
the data dash key. Now, let's go to the bottom here and console log the actual key
element. Good, look these are the corresponding key elements that we have,
and how do we get them to do that cool little animation? Well,
again, if we go back to our style.CSS we've got here, you see that I've already
styled the CSS and most of this does not matter except the one line that we have
here that is transition all 0.07 seconds. And when you add a class of playing to
that, we're going to scale it up, we're going to change the border color and we're
going to change the box shadow color. So, what we can do is we'll say,
"key.classList.add" and then we'll say "playing." If you've never used this,
if you're just used to using jQuery, that's the same thing as saying like
"key.addClass(playing)." Except we're not using jQuery here, we're just using
Vanilla JavaScript, so that's the way that you do it in Vanilla JavaScript.
You call .classList and then add. Similarly, we also have .remove and we
have .toggle which will allow you to add and remove the different classes that
you want. So let's see how that works S, D, F. You see how it's adding them?
If you want to see how it works a little bit slower, what you can do is go into
your CSS and change this, maybe let's make the scale two and let's make the
transition 1.07 seconds. Now when I hit D, you see over a second, F, G.
That's what's happening but because we did it in such a short time span,
0.07 seconds, it just does it really, really quickly and also,
we don't want to scale it up exactly that much. Now, that works but why isn't it
going away? That's because we are adding the class but we have not yet removed the
class. You might think, "oh, that's no problem, we'll do like a set timeout here,
we'll run a function here and after 0.07 seconds." Well, that's okay but what tends
to happen if you have a timeout here as well as you have a timeout in your CSS
JavaScript which is right here, they start to get out of sync because maybe like a
designer comes around like, "its not quite right, let's change that to like 0.9,
that feels a little bit better to me." And then you have to go into the JavaScript to
make that that lines up as well. So rather than like just setting a timer to do it,
what we can do is use a transition end event that will fire when the thing has
stopped animating itself on in. Now, what is the transition end event?
Well, let's take it back a second, what is a click event? The click event is when you
click something and it will fire off the event and say, "somebody clicked me." We
also have events in JavaScript that will say, "I didn't get clicked but I was
transitioned, I transition myself from scale 1 border black to scale 1.1 border
yellow." That's what we're going from here which is the border black to here which
the border is that specific yellow. So what we can do is we can listen on each
key for when the transition end event happens. So let's do that.
First, let's go down here and we'll say "const key=" now I need to select every
single key on the page because we want to listen for it on each one.
So let's say "document.querySelector" and we want query selector all, and we'll say
dot key. Now let's just see if I were to run that in my console here,
let's see what that gives us. That gives us an array of every single element that
is matched. Okay, good, then what we want to do is we want to listen for
an event called transition end on each one. So it's like "keys.forEach" and we're
going to get each key. If you're wondering why do we have to this,
like why can't we just do "keys.addEventListener" and listen for
transition end? And that's because if you're used jQuery or anything like that,
the problem is when you have an array of elements, you cannot listen on all of
them. You must explicitly loop over every singly element and attach an event
listener. So, the way that I like to that seems to be the simplest way for me is
you can say key. We use a little arrow function here, if you've followed along in
my ES6 series, it's "key.addEventListener" and then the listener that we're listening
for is transition end, and when that ends, we are going to run a function called
"remove transition." Now we have to make that. Now, let's just take a quick look
at here. So each key gets an event listener added to it which is transition
end. And then when a transition is ending, we will remove it. Now we need to actually
make that function here. So let's say "function removeTransition" and that let's
give us the event. Inside of that, we'll just console log the event just to see
what we're working with here. So, I'm going to press A. Whoa, what happened
here? Okay, so we have one, two, three, four, five, six transition end events for
that one little fade in where it got a little bit bigger. And that's because a
whole bunch of things transitioned here. The border right color transition,
all of the borders have transitioned. The box shadow which is that little yellow
glow has transitioned. And then also, the transform has finished.
Now, we don't really care about all of these. We really just want to it when one
thing is over, generally the longest one. So, let's pick the transform.
So, let's say "if E." and what was the event we were looking for here
"event.propertyName." If it doesn't equal transition then we will return.
And now we'll say "skip it if it's not a transform." Transform,
not transition, I always mess them up. Thank you for yelling at me through the
computer screen. Now, what's up next? Let's just console log e.propertyName.
Let's see what we're working with here. So we got this function that will run when a
transition has ended. You see what's happening? It's console logging the word
transform because that is the property that is being ended. Now,
that does it really quickly, but if I were again to change this transform to 2.07
seconds and press A, one, two there we go. It took seconds and then that's when it
ended. And coincidentally, why coincidentally? That's why we want to do
it. When that happens, when it's done moving itself in, we just want to reverse
everything that we know about that. So we can head to our remove transition function
here and first of all, we'll save this. Now what is this going to be equal to?
Well, if you are having a hard time understanding what this is equal to
a really cheap and dirty way to understand what this is equal to, well first you just
console log and see what it is. That's a nice a way to find it out.
So, let me press A and then after two seconds, I still have it on two seconds.
This is equal to the key, and why is that? Because this is always equal to the
whatever got called against it. So add event listener got called,
what got called against it, key. So this is equal to the actual key.
So this, .classlist.remove we'll remove the class of playing. Give that a save.
Now it's two seconds so I'm going to hit it. Two seconds later,
transition end is going to fire which is going to remove the transition of playing
and it should fade itself out. So, I'm going to hit D, it's in and it's done
and it'll take the class off. If we inspect that, watch it right here.
See, it's got a class of playing and then two seconds later, it will remove it.
Now, if we go to our CSS and change that back to 0.07 seconds,
it's just nice and quick, nice and quick, nice and quick for all of those,
it went immediately. And the same thing happens there if you were to add a class
of playing in div tools. It will still remove it because the JavaScript is
listening on that element for when you remove it. One last thing I want to do is
we go into our HTML. I'm never a big fan of attaching these functions right to the
key down here, so what I want to do is put these in its own function and it will call
that play sound. Let's say "function playSound" and put all these logic inside
here and that is going to take in the event which then bring down my event
listener down to the bottom here and we're going to say when someone keys down
we're going to play the sound, that should keep it for us. Still works fine
and that we've got them nice and separate so that if I ever wanted to play the sound
based off on something else, I totally could. So that is a basic JavaScript
Drum Kit. Again, the things we learned about was key events as well as playing
audio as well listening for the transition end event. Similarly, if you're also
dealing with animations, you can listen for the animation end event, which works
exactly the same way. Thank you so much and I'll see you in the next one.
♪ [music] ♪