FREELessons: 29Length: 8 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

2.5 Events 201

[NOISE] Now that you have a basic understanding of working with events, we're going to move up from Events 101 to Events 201. So we're going to take a look at using the on method a little bit more, and also teach you a bit about events delegation. Here's what we're going to build in today's little project. And it's simply a FAQ section where users can view a question and what the answer is, and here I've simply duplicated the content. But when they hover over it, they can see the question that is associated with it and then also any other questions will hide. So it's a nice little toggling effect where they can quickly see a bit about your company and the FAQs. All right, let's get into this. As always, I have my basic template. So let's get started with the markup. First, when creating a definition list, there's lots of different ways. You could wrap each one in a div. That way you could style it. In this case, I think I will be fine if we use a definition list. That way, we can have the term, which would be the question, as well as the details, which would be the answer. Now our question will be, what are your hours? And the answer will be, we are open 24/7. And now I'm simply going to duplicate this so that we don't have to watch it too many times. Three, four, five. And there we are. So now, of course, I need to style it a bit. And I'm gonna switch over to my style.css file. And I'm gonna set up stylings for the definition list, the details, and the terms. And while we're at it, we'll also do a little bit of styling on the body element itself. Now, I'm going to do this editing within Chrome, and I'm using a plugin called Chrome Auto Save. That will automatically save any changes I make in the browser, to the editor. For example, if I click right here on the DT, I can say color red. And if I reload the page, you'll see that, that has still remained red, and it's been applied right here. So, it's a really cool plugin to have when you're using simple projects. All right. Let's come back and get started. The first step is I want to style the details because I don't want that spacing there. So click right here and chose the definition details. And I'm going to set the margin to 0. And then I also want to have just a little bit of padding so I'll set 1m on the top and bottom like so. Next I'm going to style the term itself. And in this case I want it to be obvious that the user can click on the term so I'm going to make sure the cursor is a pointer. Next to make it stand out we'll make the font weight bold. We'll up the font size to maybe around 1.5 ms, adjust the line height. These are mostly arbitrary, just make it look a little bit nicer, and then finally I'm going to add a background color to make it look a little more block level. And we'll make that a greyish color, like so, and that looks good for now. And then I will go to the body elements and style that one as well. And we'll set a width of our body to around 500 pixels, and I want to center that on the page. Finally we will align the text to the center. Okay and that's looking fairly good for our demo, I just want to do a couple more things. On the terms I'm going to add some borders just to make them pop a little bit more. Right here I'm going to say border bottom, one pixel solid and I'm going to make this a slightly darker shade. As you can see right there we just get a slightly darker border and then we're going to do the reverse for the border top and this time we're going to make it lighter than the main color. And we'll say one pixel solid white like so. And that will really show its effect once we hide the details. All right, so I'm going to close this out, reload the page, come back to our editor, and that's all been automatically saved. Isn't that a cool little plugin? You can research Chrome Auto Save if you wanna use that in your projects. Now if I come back to our main page, we're ready to get started and have some fun. So we will begin again by creating a self invoking anonymous function. You might want to save that to a snippet to save some time. And the first thing I wanna do is hide all of these details because we only want to see the first one. So we can do that easily. I will begin by creating a variable called dd, and that's going to reference all of the detail elements. Next we're going to hide them, and we have a couple different ways to do this. One, we can simply call the hide method. We could also use the show method, jQuery offers lots of different ways to toggle the display. Dd.show if you want to fade it in, dd.fadeIn if you want to slide down. If it's hidden and you want to show it. Dd.slideDown. And then there is the inverse, slide up, fade out, hide. And then there's also toggle, which would mean maybe you click on a button. And when you click on it once, you want to show it. And when you click on it twice, you want to hide it. In that case, you would use the toggle method. And that simply means if it's visible, hide it, if it's hidden, show it. And we will be playing with those quite a bit more in future lessons. So once again for now, let's use dd.hide. Reload the page and those have been toggled. And now we're starting to see our borders but it looks like my white border top is not showing up, and it's not. Looks like that didn't get saved. All right, so let's add that to border-top. Reload the page and now we're getting just that slight stairstep effect. However you'll notice at the same time we're still getting a border of bottom at the very last one, and you likely don't want that. So if you do want to hide that you could say dt, get the first child, and border-top, hide it. And then you would do the same thing with the bottom and that way you don't end up with these extra accents when they don't really apply. But you might think you could do something like last-child and then switch that to border-bottom, but that's not going to work. And this is something, CSS specifically, that trips a lot of people up. Why would that not be working? We're getting the definition term, we're getting the very last one, and we're hiding the border, but it's still there. And that's because of the way last-child works and this will apply to your jQuery as well. So I don't mind covering just a little bit of CSS here. The idea is when you're calling last child, it's not specifically looking for what you pass. For instance, when I say dt last-child. What it's looking for is the last child of the parent. Now, it's saying only select this dt last-child, if it is in fact the very last child of it's parent. The parent is the dl. But, actually, the last child is the definition details. So that is what's being selected. This is failing, so this never launch. That's the basic idea. So that begs the question, within a definition list, how would you select the last definition term? And one way that we could do it is to go back. So you could say, dt. And this is a rather advanced pseudo selector. We're going to say if last child, so you know have nth child, where you start at the beginning. But with CSS 3 you can also go in reverse. So now I'm going to say last-child(2). And now what that's gonna do is it's gonna say, going from the bottom, get the last child and then we're going to pass 2, which means get the second to the last one. I come back, reload the page. Now you can see that that has been removed. If I open Chrome Developer Tools. You can see here that when we call hide, it is applying display none to the styled attribute to each one of those. If you would prefer to do a different way, you could also in your style sheet add a helper class. Hide {display; none;}, come back and then rather than calling .hide you could say dd.addClass{'hide'}. If I come back, reload the page, you're going to get the exact same effect, except this time we're applying a class. So which technique do you use? Again, really depends on the situation. Now here's the next thing. I do want the definition for the very first one to show. When the user loads the page we do want to show the question and answer by default, so we don't want to hide every single one. Now again, lot's of ways to do this. I want to show you a way using the filter method. Because this is one that you haven't yet taken a look at. Now in this case dd, we're going to filter this selection down. Right now it's selecting every single definition details in the dom. We're going to filter that down. Now filter, think of the filter and everything we pass into it that meets certain criteria will then be passed to the next method that you use. Anything that does not match that criteria will be filtered out. So in this case we're going to filter those down and we're going to say we only want nth-child(n plus 4). And only those which match that criteria will receive the class of hide. So let me check that. That is working. Now let's explain it. Nth-child(n plus 4), that's a little scary. It's really not though. We are saying, we want to select the fourth one minimum. You can work right to left to understand these. So we're going to say, one, two, three, four. That is the first definition for the second question. So that would refer to the definition for this question right here. And then we're saying n plus 4. So we're essentially saying begin at that one, and then I want you to select every single one, n plus 4. So that's going to select every single details that follows that. So as long as it meets that criteria, those have a class of hide applied. But these do not match that selection. But this first one does not match that selection, so it does not receive the hide class, and it shows by default. Okay, so, so far we've done a lot of HTML and CSS. Now, we get to move into the events part. Now, we'll do it the easier way, and then we'll improve upon it when we're done, as we did before. So, I want to say, when the user hovers over a definition term, we want to show the details that follows it. So we could use hover, or we're going to use that on method that I said before. Now, hover is a convenience method. It's not specifically an event. So we're going to use mouseenter instead. When the user's mouse enters a definition term. We're going to get the definition term that was hovered over. We're going to get the element that follows it and we know that the details will immediately follow it, and we're going to show it. Come back, reload the page. When I enter it, we show it. But now you can see as I hover over each one, we're showing every single thing so after a few rounds, every single details is showing. What we really want to do is toggle them. When I hover over this, everything else hides. When I hover over this one, all of the other details hides. So how could we do that? Well, what if we tried this. I'm gonna duplicate just so it's a little more readable, and then we'll clean it up. What if we said (this).next, now we're referring to the definition details. And once again, we're going to get all siblings of the details. And we will hide those. Let's see what would happen if we did that. There we go, and that seems to be working just fine. So let's come back and clean this up. Certainly at this point, I hope you can see that, this is bad. We're using (this).next, and then we do the exact same thing again. We keep repeating ourselves. Never repeat yourself. So, here we're going to say (this).next. Now, we're getting the details that follows the term, then we're going to get all other details that are on this level and we're going to hide them. But then, once again, we use this next show. So, I'm going to remove that entirely and we'll say, right here, this.next show, like so. Let's come back, reload the page, hover over it. And now we're getting that effect, pretty easy. All right, so now let's add a little bit more animation. What if rather than hide, we used slideUp? One more time, hover over it, and now you can see that each one slides up like so. Now you can pass a value. It will use a default value. But we can also say slide up over the course of 2000 milliseconds, or two seconds. So now when I do it, you'll see over two seconds, the ones that follow it will slide up. You don't want to do that of course. Usually keep it around 300 milliseconds seems to be nice and snappy. And then rather than using the show method, we will use slideDown. And you know what, let's change these even faster to make them 200 milliseconds. One more time, hover over it, there we go. Down, and there we go, looks good. So now that our final product is essentially finished, there is some improvements we could make. For example, something I want you to be aware of is when you hover over these quite a bit, sometimes you'll see that the animation can repeat itself. I'll show you how to do that in future lessons. Don't wanna flood you too much just yet, but let's come back and refactor the code just a little bit. And the main things I wanna focus on are two specifically. First, we're creating a variable called dd but we're only really using it once. So if that's the case, there's nothing wrong with doing it like this. And getting rid of that variable entirely. And the next one is I want to take a look at Event Delegation 101. In this case right here, we are attaching an event listener to every single definition term on the page. And it's very possible for an FAQ section to have 50 to even 100 questions. So what we're doing here is we are attaching an event listener to potentially 100 definition term elements. Why would we do that? Wouldn't it be easier if we could attach one event listener to the parent and then determine what specifically was hovered over? If it was a term, do the actions here. If it wasn't, don't do anything at all. I mentioned how much better for performance that would be. Rather than attaching 100 event listeners, we attach one. And jQuery makes this super, super easy by sticking with the on method that we already know. The only difference is, rather than attaching the event to all of the definition terms, we attach it to one parent. So in this case, why don't we attach it to the definition list itself? Or if you need to restrict that to a single definition list, you can add an ID or a class, or something specific like that. Then we're going to say, on mouseenter, but now we're going to provide a selector string so that we can specify exactly what we're looking for. And we'll set that to dt. So, how this reads now is, when the user hovers over a definition list anywhere in this section. When that happens, we are passing a selector string, and we're telling jQuery, I am only interested in running this call back function on the condition. And I forgot a semicolon there, on the condition that what the user hovered over specifically, the target, is a definition term. If it is anything else, and in this case it would be a dd. If it's anything else, I don't care. Ignore it. But if it is that term, then follow through and call this callback function. In which case we are going to toggle everything. All right, let's try that. Hover over it and we're getting the exact same effect, but we have considerably improved performance because now we've attached one event listener to a parent. Rather than potentially hundreds to lots of children, and that's something I want you to get in the habit of doing. Luckily, jQuery makes this incredibly simpler. It can be a little more difficult with vanilla JavaScript, so you're very lucky in that regard. Okay, and I think that's gonna do it for today. We've covered a lot of cool concepts. You've learned a little bit about nth child and nth less child. Working with event delegation and how to build the obligatory accordion. I'll see you in the next lesson.

Back to the top