FREELessons: 19Length: 2.9 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

7.2 Building a Better Accordion

Our first accordion script worked, but it relied upon jQuery's JavaScript-based animation capabilities to animate the elements. In this lesson, we'll combine just about everything we've talked about in the last few lessons—selecting elements, Ajax, and CSS transitions—to build a better accordion script.

7.2 Building a Better Accordion

Well, the time has come to take the concepts that we have been talking about over the past few lessons, and apply them. And we are going to rewrite our accordion script. But using pure JavaScript, pure DOM, pure CSS as well as Ajax. We're going to use Ajax to retrieve the data and then build our HTML based upon that data. So if you'll remember in the first version we already had our dl element here. I believe the class was set to accordion, and then there were dt and dd elements inside of this dl element. Well, we're going to build this dynamically based upon the data that is inside of this accordion-data.json file. So this is an array that contains three objects, and each of these objects have a title and a description. I'm just going to refer to these as item objects. So we want to retrieve this file and then we want to build our HTML. So we're just going to jump right in because we have a lot of ground to cover. So the first thing we want to do is retrieve our data. So we are going to use the fetch function and we are going to request accordion-data.jason. We have a promise object here so we say then. And then we will get our response but that's not enough we also need the JSON as well. Now we could get the text and then manually convert that into an object but instead we are going use the JSON method. So that we can then get our data and then we will build our HTML based upon this data. Now let's write a function for building our HTML because we could do this here but we are already in three levels of nesting, I don't want to get any farther than that. So let's write a function called buildhtml, we are going to accept our data, and then we are just going to build our HTML using strings. We could use the document object to create our elements and then add them to the documents, but I want to use a new feature called template strings, because it's a cool new feature that's we should use. So we're going to start by creating a variable called HTML, and this is where we will begin with our dl element. And we had that class of accordion, so we will add that, and this is all we need for our opening tag, let's go ahead and write the code for our closing tag. Now we're going to use a template string here. Now normally we would do something like this. We would say html = html, and then we would concatenate that with our closing tag. And this is what that would look like. With a template string we don't have to do this concatenation, because with a template we can use actual JavaScript expressions within our string. So let's get rid of this, we begin a template string with a back tick. It's not a single quote, it's not a double quote. It is a back tick. And we close our template string with a back tick. And then inside of the template string, we want to refer to our HTML, so we say ${html}. So we are including our existing HTML right here directly within the string. And including the closing dl tag and that in a nutshell is a template string. We can use actually Java script expressions with in a string with out having to can concatenate or escape or anything like that. So now we want to build the individual dt and dd elements and we have this data which is an array and this is a actual JavaScript array. So we have the actual for each method here. So our poly fill isn't being used in this case we are using the native for each method and we have to pass in a function. We're going to call each one of these things an item and we are going to build our dt element. So let's go ahead and say HTML =. We're going to use a template string we want to include our HTML and then our dt element. This is for the title, so we are going to say $ opening curly brace, item.title, closing curly brace. And then our closing dt tag and then we will essentially do the same thing for the dd element. Except that the element name will be dd and instead of saying title we will say description. So by the time this is done we will have our complete HTML. All we need to do is add that to the document. So we will say document.body and we're going to use a method called insertAdjacentHTML. This will allow us to use our HTML string and insert that into the body, otherwise we would have to create like a div element or some other container element. So that we could set its inner HTML to our HTML and then we would have to add that container element to the body. This is just much easier. Now the thing with the inner AdjacentHTML method is that we have to specify the position. And there are several values that we can specify. I am going to use the value of afterbegin. So here they are, we have a before begin value, which means that it's going to insert the HTML before the beginning tag. So if we said before begin It would be inserted before the body tag and after the closing /head tag. By specifying afterbegin, it's going to insert this HTML after the beginning tag. So it's going to go in between the beginning body tag and the beginning script tag. There is a few other values for setting them above and below the closing body tag but we won't worry about that. Since we want after begin, that's what we're going to use and then we will pass in HTML. So if we wanted to make sure that this works right now, let's hop on over to the browser, let's refresh. And there we have our HTML, and if we inspect this, let's right-click on item 1, Inspect. Then we will see that we have the body tag. Then we have our opening dl tag. Closing dl tag and then our script. So this is exactly where we want this to go. Now that we have our HTML, let's go ahead and start with our CSS. So the first thing we want to do, Is set the cursor to a pointer whenever the cursor is over the dt element. That way it's signifies that hey, you can click on this thing. So we will say dl with the class accordion, that way we only work with the dt elements inside of our accordions and we will say cursor and that's going to be pointer. But we also need to style our dd elements, and we need to hide them initially. So we can do that by setting their height to 0 but that's not enough because if we do that, in fact, let's go ahead and save that and refresh. Well we can still see those descriptions. So we want to set overflow to hidden, and we can go ahead and set the transition here as well. Now we could create another class strictly for the transition, but the way that we're going to implement this is by not using any classes at all. So we're going to transition the height. Let's use the amount of time of 200 ms and the ease function. Now if you remember, whenever we wrote the first accordion, we signify that an item was active with a data dash active attribute. So that's how we can determine the dd element that we want to show. So our selector is going to be dl.accordion once again, but we want the dt elements that have an attribute of data dash active. And then we're going to use the sibling selector + dd, that way we get those DD elements and we will set the height to let's do 20 pixels. You know what, let's do this, let's say body. We'll say font-size and let's do 1.25 ,that might be a little bit too big, but let's see. Well that really didn't do what I thought it would. Let's change that to 2.25 there we go, that's a little bit better but we're going to need to change the height I believe. Let's do it 50 and we might have to change that again but at least we can see this a little bit better okay. So now we just need to write the JavaScript code that's going to add this data-active attribute to the active dt elements that we click on. So that means that we need to select our dt elements so that we can set up a click event listener on each of them. So let's do this in another function. And we will just call this init. There's many other things that we could call it but init is going to be fine. And so we will have function init. We want to retrieve our dt elements. So let's save our dts = Document.querySelectorAll and we want those dt elements that are in a dl element with a class of accordion. So that will give us those. And then we want to iterate over those. So we use forEach. Now our forEach polyfill is coming into play. And we'll say that's for each element in our dt's node list. We want to set up a click event listener and let's write a separate function for this and we'll call this dtClickHandler. So let's take that, we will write that function and we will start by retrieving the target of the event, that is the dt element that received the click. So we will say target = e.target. But we also need a reference to the dl element that contains that dt element so we want the parent. And we can do that with our target. This has a property called parentNode. And that is our dl element. Now the reason why we need our dl element is because we want to find any existing active dt element. And we could use the document object to do that but that's going to search the entire document. Instead we want limit the amount of our search to just the dl element that we are working with. So we will do this let's create a variable called active we will say dl and here we will use our queryselector method. And the reason why we can use query selector it's because it's not unique to the document object it can be used on any element. So we have a dl element, we can query within that element and we want to find the dt element that has the data- active attribute. Now it's possible that we don't have one. Because whenever the page first loads, we don't have an active elements. So we need to check to see if active Is not null because if it's not null, then we have an active element and we need to remove that attribute. So we will say active. We will call the removeAttributes method. And we will remove data-active and that will clear out the current active item but then we want to set whatever it is that we clicked on as the active item. So this is where we use our target this is what received the click event we'll say set attribute we'll say data-active is equal to true and that should be it. So the moment of truth let's go to the browser, let's refresh the page. If we click on these things, [LAUGH] it works at least the first time, it worked. If we click on these other things we can see that those work as well. So we have recreated our accordion script without using jQuery, we used pure JavaScript, pure DOM and pure CSS and a little bit of Ajax and it didn't require, well, that's a lot of extra code. But some of it was building the HTML. It certainly required a lot more code to initialize everything, but we do have the benefit of not using any library whatsoever. So this code will work for as long as the standards are alive. Now, one thing I should note, as I was editing the last lesson, I saw that the animation was a little choppy and that was primarily because of the frame rate that I record these videos at. They record at 15 frames per second which is not very good, as far as animation is concerned. So these animations are very smooth on my screen. And as you write them on your computer, they will be smooth as well. Viewing the video, however, it's going to be a little choppy just due to the FPS. So don't let that discourage you from using CSS transitions, it's actually the best way to have animation within your applications.

Back to the top