FREELessons: 29Length: 8 hours

Next lesson playing in 5 seconds

  • Overview
  • Transcript

3.7 The Obligatory Slider (First Attempt)

[SOUND] It wouldn't be a jQuery course if we didn't cover the process of building the obligatory slider. So, over the course of the next two lessons, we're going to build the same slider, but in each lesson we'll structure the code slightly different. Today, we will take a look at more of a procedural approach something that will be very familiar to jQuery users. And in the next lesson, we'll take a look at prototypal inheritance which provides a little bit more structure for your code. Now here's what we have, we don't have any design associated with it. That's your job. Your job is to style the buttons and make it look pretty. My job is to teach you how to create the functionality. So, there's a few things worth noting here. We have Previous and Next buttons, and when I click on them, we're gonna go through each image. And then we have a total of four images in this example. Once you get to the last image, when the user hits next again, we need to have the logic that will bring us all the way back to image number 1. So it needs to know when we're at the end. And alternatively, if I hit previous and we're on the first image and I hit it again, it needs to know to go to the last image in the set. All right, let's get into this. This time, because we're starting to get into slightly more complex code rather than pasting everything into our index.html file for convenience, we're going to abstract these out. So I have a slider.css file. And that will handle any specific code needed for the slider to work. And then we'll also have a slider.js. And as you can see, right now, both of them are blank. So the first step is we need a wrap for our slider. So I'll create a div with a class of slider. And within it, we're going to have an unordered list of images. Now you'll see that I have an images folder here to the left and we have four images. And each one simply says image one, image two, image three. So let's go ahead and add those in. We'll have an image that links to I-M-G slash I-M-G one dot gif. Give it an Alt of something generic, and then I'll duplicate that three times and we have 2, 3 and 4. Let's view that in the browser. Okay. So, now, we just have this big list of images, but that's not gonna help us. So the next step we need to take care of the navigation as well and we'll place that below. And this time we'll give it an id of slider-nav. But feel free to give this any name you want. Now, we could do anchor tags. But if you think about it, if Java Script is disabled, those anchors serve no purpose. They're not leading you to any other site. They're simply triggers or they're buttons. So with that in mind, why don't we stick with using a button. And the first one will be Next, or it might make more sense for the first one to be previous and the second one to be next. But now, I'm thinking already, we're obviously going to respond to when the user clicks on the button. So, I need a way to know whether they clicked on the previous or the next button. And we could check to see what the text is. But then, I'm a little limited if I want to later change the back button to "back" or "prev," that breaks my code. So instead, we're going to use custom attributes, and we'll say data direction is going to be "prev. . And here I'll do another one, data direction equals "Next." These are HTML 5 custom attributes, but they'll work in any browser. It's not problem at all. Worst case scenario, some validation gets made at you but you don't need to worry about that. Lets come back load the page and at the bottom we now have our buttons. While I'm thinking about it if JavaScript is disabled we do not want those buttons to be visible cause they're not going to do anything. So I'm gonna go to slider dot css and the very first thing slider nav. I'm gonna set a default display to none, that way if Java script is disabled, they don't see it, they're not trying to click on a button, but if it is enabled, we'll use Java script to show those buttons. A few lessons back, I showed you how to create these buttons dynamically and throw it into the [UNKNOWN]. This time we're taking a sightly different approach by adding them and then using the display to adjust whether they are visible or not. Now, let's take care of a little bit of generic styling. I went to limit slider dot css for slider specific code. So normally you would also have maybe a style dot css as well. But we don't, so we'll just place this as a style at the top since we don't have very much. And I want to give some base styling for our little project and we are going to set a width of 600 pixels. And the reason I'm doing that is it's just a nice even width. And also each of our images are 600 pixels by 300. So that way, we can perfectly center our images on the page. So margin, I'll push it down about 100 pixels or so. We'll set the left and right margin to auto and the bottom margin to zero. Let's see how that looks. There we go. Now, they're centered on the page. Good. And the next thing is, just for convenience, let's do a very quick reset here. Margin and padding to zero, and that way we can zero out anything that might exist on the unordered list or list items. Refresh. There we go. And that should be fine for our generic styling. So the next step is, we can go into our slider.css file and continue. And I'll go ahead and switch to full screen now. So we have slider nav and the next step is we're going to target the slider wrap. And you might be wondering why do we have div with a class of slider and then an unordered list. Why don't we simply have something like this? Wouldn't that be better? And yes, if you can get that to work, that would be better. But the way we're going to do it is we're going to set a specified width on our wrapping div and then we can style the unordered list to make sure that we can have a width of 10,000 pixels and it still looks good and we're able to scan these. And that'll make a little bit more sense as we get into it. So I will switch back to style.css. And we'll go ahead and style the diff with the class of slider. We'll begin by setting a width. And I will simply half it inherit it's width from the body so that will be equal to 600 pixels. And next, I'm going to set a heighth of 600 pixels as well because we know our images should be 600 by 300. Next, let's switch down to the unordered list. And this is the real wrapper for our images. So I'm going to set a massive width, 10,000 pixels to this, and then I will also set list style to none to remove the bullets. So now if I switch back and I reload, you'll see that technically, we can just scroll as much as we want. And that may seem unintuitive, but watch what happens. When I come back to slider and we've given it a width of 600 pixels, and now I'm going to say anything beyond that we're going to hide overflow hidden. So what that does is now even though the un-ordered list has a huge width we can't scroll and we can't see it. But if I open up Chrome Developer tools, you'll see that that width is still 10,000 pixels. So, now the basic idea is, we can go ahead and grab those list items and we will float them to the left, so now you can't see the effect. But if I do open up chrome developer tools, we can see if we go to a list item, right here, you can see the second one is off to the right. And if we scroll it even further, the third one and the fourth one, so now we have them in a line. And we can simply adjust the margin of the unordered list. To give you an example, let's go to the slider to the ul, and now I'm going to set margin left equal to the width of one of these images, which is 600 pixels. But if we set that to a positive number. That's going to be pushing it to the right. We want it to go to the left. So, we'll set it to negative 600. And now you see Image 2. If we set that to double the width of two images, 600 times two, we have 1200. And now we see Image 3, Image 4, et cetera. Next let's come back to those buttons and provide just a little bit of styling for them. Right now they're hidden but when they are visible, I'm gonna give them a little bit of margin on the top and we'll keep it at that. And finally, we will style the buttons, and the buttons should have little bit of padding around them. Give them some margin right so they're not right up against each other, and do a little border radius, maybe 10px. And I do want the user to know that they can click on this button, so I'm going to set the cursor equal to pointer. Now if I come back up and we uncomment out the display none, you can see. Let's go back to normal size. There's our buttons, very unattractive, but we simply need something to click. It's your job after you finish this to style these and place them wherever you want, make it look good. Now, we get to dig into the fun part. So, once again, I will make those buttons hidden so all we see is the images. Now, this will represent how the page will look if JavaScript is disabled because we haven't written anything yet. So if that's okay with you, fine. But if you do want to give the user the ability to scroll and look at those images you can always change overflow hidden to overflow. Scroll, and then they can have the ability to scan all of the images like so. That way if JavaScript is disabled, and that's going to be a very low percentage, they can still scroll and take a look at everything. But then if it is enabled, we can update that to "overflow hidden." All right, let's get started. I'm going to open up "slider.js," and you can see we are importing that at the bottom. And it's simply a blank page. And we will begin. Now, it does make sense if you will use this type of slider in lots of projects to brand it as a plugin. But I don't wanna get into that territory too much until we actually discuss plugin development. So for now we're gonna take more of a procedural approach. The first step is, as we've been doing, wrap our code in a self invoking anonymous function. And also once we get to this point where people might be using our code, it's possible that they may be using a different Java Script library where perhaps the dollar sign doesn't refer to jQuery but it refers to something different. So it's fairly common with some scripts to import jQuery into a function so it's available as a local variable. So, we'll take the long form of jQuery. And then it's going to aliased, quote on quote, as the dollar sign. That way we can use dollar within here, but out here it's possible that if there's a different JavaScript library, dollar may refer to mootools or prototype or something similar. It's a small bit of protection. Okay. So, the next step is to get some variables going so we know what we're working with. We begin by grabbing the sliderUL. And what we wanna grab here is the div with the class of slider, and I wanna get this wrapping on ordered list. So let's come back, and we'll say var sliderUL. It's going to be equal to jQuery, get the div with the class of slider and we'll get the children, that's a ul. Now in this case, we could also do div slider ul, something like that. But it will be fractionally better for our performance if we do it this way. Next, we need to hold onto the images. In the images will be a list of all images contained within that un-ordered list. So we'll make that equal to slider UL dot find IMG. Next, I need to know the width of these images cuz that's going to determine how much we transition every time a user clicks on a button, and that's why each image will need to be the same width. In our case it's gonna be 600 by 300 but I don't want to hard code this in because then, in the next project maybe the width of these images in our slider is 900 pixels and our code breaks. So I want to figure this out dynamically. So instead I'm going to say, IMG width is going to be equal to the images, and right now that represents the images wrapped in the jQuery object. But if you ever want to, sort of break out of the jQuery object and just get back to the node, regular java script, you can do it like so. And now that we can simply reference width. We could also do this as images, dot first, dot width or we could also get rid of first and if we call width on the images object it will simply return the width of the first image. Now alternatively, we could also use the CSS method and return the width of the images like this but the difference is, if we use the CSS method to return the width. That will return 600 pixels in our case. However, if we stick with width that's going to return 600. And that'll be much easier to use when performing math calculation. So in this case, lets not do any more work than we need to. So lets just use JavaScript's dot width on the first image node. Next, we need to know the total number of images that we are working with. So, we've referenced the images right here. Let's get the total number of them. And we'll I-M-Gs length is going to equal to I-M-Gs dot length. This is a method that will simply count the number of, in this case, images in the collection. And in our case, if we come back that's going to be equal to four. So we can grab that number with dot length. So at this point that would be four. I'm going to hard code these in just to make it a little more readable for you. And then we just need to do a couple more. Don't worry, I'll make all of this clear as we move on. We need to keep track of the current image. And by that I mean, when the user clicks on the button, they'll go to the second one. And I wanna keep track of where the user is. So, when they click on the button, I wanna keep track. Now, they're on the second image. Now they're on the third image. Now they're on the fourth. And if they click, prev, I need to update that so I know, now they're on image three, image two. So that's what current is going to store. And by default, we're on the very first image when the page loads. So I'm going to make that equal to one. And then finally, we're going to do one last variable called total images width. And that is going to be the entire width of all of the images combined. And that's how we will know how wide all of the images are together. If we have four images and each is 600 pixels, we know that the total width of all of those images would be 2400. So we can grab that value by doing the total number of images, images length, times the width of each image. And we're going to assume, and they should be, all the same width. There we go. So now that our variables are created, we don't have to grab the slider all of these different times in our project. We don't have to figure out how many images we're working with over and over. We've quote unquote cached them at the top. So that we only do those operations once. The next stop is to listen for when one of those buttons is clicked. So we'll get the Slider nav. And the first step is, if you'll remember, we hid it by default. So I'm going to show it with JavaScript. Good. And while we're here, we should also update the overflow scroll to overflow hidden, so we can reference that right here. See assess, overflow to hidden. Come back, refresh, now we've updated the overflow and that's good for the Java script. Now in this case, if you're confused, we're grabbing the diff, the class of slider, and yes we are updating CSS property. But then after that because we can chain with jQuery, we grab the children and that's what's returned to the slider UL variable. So there's nothing wrong with a quick operation here. Okay. So, let's come back to the buttons now. We are showing the slider nav. The next step is to find those buttons, so we could use children or find. Most of the time, you don't need to pre-optimize there, and you can have a little more flexibility if you stick with find. Now, we're going to find one of these and listen for when the button is clicked. So at this point, we'll clicked. Open up Chrome developer tools. I will click on a button and sure enough we do get click. So everything is going according to plan at this point. The first step is we need to figure out are we clicking on the next button, or the previous button. And if you'll remember, if we come back to index.html, we stored that with in a custom attribute called data dir. So if we'll come back, we can capture that value by saying var direction equals get the button that was clicked and get the data dash drawer attribute. So we could do it like this and that would work if we console.log direction and then logged that, we will get next and prev, but jQuery makes this a little bit easier as we've learned. We'll stick with the data method, slice off data dir,, and now we can access it that way. One more time. Next and we get the same effect. Good. So now we know whether we need to move forward or backward. Now at this point, the user has clicked on the button. We need to keep track of where they are in that set. So that's going to be my next step is update current value. So how can we do this? Well, we can say if direction equals next, that means they clicked on the next button. And in that case, we will say current equals current plus one and we're going to improve this and shorten in just a moment, but for now we'll do it the long way. Else, current equals current minus one. That means if the user clicks on the Next button, we are going to transition to image number two. So we're going to take current, and we're going to add one to it. So at that point current equals two. However, if they did not click on the next button, they clicked on the previous button. So, in that case, we need to reduce it. And in that case, current would be set to 0. And that's something we need to be careful of. We do not want to set current to 0 or negative 1 or negative 2, so we need to have a bit of logic to take care of that. Now let's refactor this. There's absolutely nothing wrong with this, it's probably the most readable. But, if you work with Java script a little bit more, there are ways that we can shorten this. One of these is to simply do this number right here, plus equals. And when we say current plus equals one, it's the exact same thing as saying current equals. Current plus one. It's shorthand. So we can take both of these and replace them like so. Now in this case, we're not doing plus equals negative one, we're doing minus equals one. Now in this case, we are doing about four or five lines for a simple operation. So if you would like to instead use the turn area operator. We can do that as well and we can simply have a test and if that test returns true, we do something, and if it returns false, we do something else. So in this case, our test is direction equals next and if that is the case. We are going to do current plus equals 1 and if that is not the case we do current minus equals 1. And now we can get rid of all of that. But we can even shorten this a little bit more by doing this number right here. Now as you're gonna learn with JobScript as you stick with it more and more. As you shorten your code, you also make it less readable. And readability is far and away the most important thing when you're writing this code, because you need to be able to come back to it in a few months and know what it's doing. That said, if you can fully understand this, you can stick with it. If you need something more readable, use what we had before. Now what we're doing here is we can add a number. So for example I have myValue here. We'll go on a quick tangent. And if I do this right here that will read the value and then add one to it. So if myValue = 1 and we consol.log this. Like so. And I'll comment this out. What do you think will be logged to the console? Let's try it. Click on the button and we get one. But I thought we added to it. I thought that was the same as my value plus one. Let's try that. Click on the button. Nope, it's not quite the same. What this is doing, though, is it's reading the value out. So it finds my value is one, it reads that value out that is logged to the console, and then it increases my value by one. So then if we were to do the exact same thing after it, you'll see that we get one two because by the time we get to this second console dot log, my value has been incremented. And the same thing is going to be true for minus minus. Click it and we get one zero. Now, if we instead place plus plus at the beginning, that will increase my value by one and then read it. So we're doing the increment before it is read. So in this case we're going to get two two. One more time, click on it, and now we get two two. Hopefully, that makes sense. So, what we're doing here is, we're saying if the user clicked on the next button, then increased current by one, because they've clicked, they wanna go to image number two. So current needs to be incremented by one. However, if they did not click the next button, they must have clicked the previous button, in which case we reduce it by one. Now, let's do a quick check here. And again, we're doing this mostly procedurally today to make it as readable as possible and then we will rewrite the code in a following lesson to make it better. And then ultimately, we will turn this into a plug-in in the plug-ins chapter. So, we'll say, if first image. Now, we do not want to set current to 0, or negative 1. That doesn't make sense. So, let's do a quick check there. And I'm gonna say, if current equals zero, in that case, we want to switch to the very last image. So they're on the first image. Think of this in your head. They are on the first image. They click the back button so we want to redirect them all the way to the last image in this set. That way they can infinitely click back. And it will simply filter through all the images then go back to the last one and filter again, so if they click back, then we're going to set the current equal to the last image in the set. And how can we determine what is the very last image in the set? Well, we already determined that. We catch that value and that is equal to four. So we're going to essentially set current to the last image, or I M Gs length. Next, even though the user clicked the back button, what we ultimately want to do in this condition is send them forward. So I am going to update the direction variable to next cause right now, it's equal to previous. So we're going to update that and take we'll advantage of that shortly. Now, what if current is not equal to that? Well, what if it equals current minus one equals the total number of images. And if that's the case, the user is on the very last image. So think about it. If current minus one, is equal to the length of images. That would mean they are on the very last image in this set, and in that case we need to do the opposite. We need to send them all the way back to the first image. They are on the fourth, they click next, so we need to go all the way back, like resetting to the first image again. So in that case, we set current to one and finally, we need to execute some kind of function that will perform this animation. So we'll call a function called transition like so and we'll go ahead and create that right here, function transition. And this transition function is going to receive a handful of arguments. The first one is going to be the container, what are we manipulating? What are we animating? So we want to animating the sliderUl variable right here. So when I call that, I'm gonna pass in a path to that element that will be animated. And the next option is, where are we transitioning to? What are the coordinates or where is the location that we're going to be moving to? And I'll store that and we'll call it Loc for location. And the third parameter should be, are we moving forward or backward? And the reason we're doing it this way is because rather than having lots of animate methods,one that will send us forward, one that will send us back and one that will reset we can store all of that once. And we don't repeat ourselves and keep writing all of these multiple animate methods. Now we can pass direction so we'll leave that blank for now. But we can pass the direction because we've already received it here. So at this point we're calling a transition function. We're passing in the the path to the unordered list that wraps our images, and we are also letting transition know are we going to the next image or the previous image. So let's next tackle the core dense issue. We need to be able to tell the transition function. Where we are headed, where are we going? So by default, we are going to create this variable loc for location. I'm going to just hard code that in as img width. So by default, that is going to be equal to six hundred pixels. Because if you think about it knowing that value when we call animate. We can use relative animation to adjust the margin left by 600 pixels from its current value. So when we call container.animate, we can animate the margin left and make it equal to minus equal 600 pixels. That way it takes its current margin left, and we are subtracting 600 from it. That's the basic idea. So if we store the location, but we need to update it on one condition, and that condition is if we are at the end. Are we at end? Should we reset? So, if that is the condition, we have updated the current image because now we want to switch back to image number one and we're also going to tell the transition function. That the location it should go to should be zero. We wanna send this back to zero pixels, essentially. So we more or less want to say march and left is zero on the case that we need to reset. Because this number will keep going up. The first time you click it, it may be negative 600 and then it could be negative 1200 then negative 1800. And if they are at the end we ultimately want to update to zero and essentially reset. So now that we've factored that in, we can pass that location here. So now container is the slider UL, location is either going to be 600 or zero and the direction will either be next or previous. So let's come down to the animate method and for now, again, I'm gonna hard code this in minus equals 600, and let's see what happens with that alone. I'm gonna click next and we do transition to the next one, and we do it again so already it seems like it's working, but we get to image four and I click it again and because we're simply using a relative, once we get to that fourth image and we click it it's going to adjust the margin left. But now there are no more images, so we can keep clicking this, but now there's nothing else to display, and that's why we had this check right here to detect when we are at the last imagine. And if so, reset back to the first one. Now I noted that we only wanna write the animate method once so that we don't repeat ourselves. And that's why we pass direction right here. And this way we can figure out whether we need to use minus equals 600 or we need to add 600 to the margin left. So we'll do this at the top end. We'll create a variable called unit and this will either be minus equals or plus equals. And that way we can [UNKNOWN] by doing unit plus 600 and that would ultimately translate to maybe minus equals 600, something like that. So we've declared our unit variable and now I'll say if direction, we're going to make sure that was passed and the location that we're directing to isn't zero. And in that case we know that we need to use relative values because if location is 0, we simply want to go immediately back to 0. We don't want to use minus equals 0. We're going right back to margin-left is 0. So we're gonna make sure that we only do this on that condition. In that case we update unit. And that's going to be equal to either minus equals or plus equals. So we'll say does direction equal next. If that's the case, once again we're using the ternary, we're going to make that equal to minus equals. Otherwise, they clicked on the previous button, which means we actually need to add to the margin left to get it to go back to the right. And we'll set that to plus equals. Finally, we call container dot animate. We adjust the margin and we set that equal to one more unit. We'll set that equal to unit plus location, otherwise we'll set it to loc. So I know this seems a little more complex but the reason why we're doing it this way. Is so that we can handle a lot of different options. We can handle it if we need to go forward or if we need to go back, or if we need to reset to a specific number. So, at this point, let's go over it one more time. Unit, as long as the user isn't trying to reset, unit is either going to be equal to minus equals or plus equals. So then we animate our container which is the slider wrap. And we want to adjust the margin-left. So what we say here is, is there a unit value? Because it's possible that this fails and unit will be equal to undefined, so is it not undefined? If that's the case, then we set it to unit plus the location or the coordinates, and that will essentially translate to minus equal 600 or plus equal 600. However, if the unit is undefined we need to reset it. In which case, we set magin-left to zero and that's represented right here. So let's try this out. Refresh. I'll click next. We go to the next one. I should could prev and we go to the previous one. Now, here's the trigger, if I click previous again, if we wrote it right, rather than showing us a blank screen, it should bring us all the way up to image four. But nope, that's not working. It just directed us back to image number two. So we need to debug this. And we can debug it right here. We had this comment if we're on the first image, and in that case, they click on the back button, we wanna take them all the way to the last image in the set. So we did correctly update the current to be the very last image in the set. But we never updated the location the transition should direct to. So let's update that right now, and we'll say the location or the coordinates that we're updating to should be equal to total images width. So now remember total images width is 2400. And that should be, so we think, the right value that we need to direct to. But as you're gonna find, that's not quite right. Let's try it out, though. Click on next. Click previous. Click it again and it does go, but it goes to up too far. Well, why is that? Well, we set the location equal to 2400. But really if you think about it, we want that location to be 1800, because we have to factor in the width of that final image. So if we transition to 1800 pixels, and then we add the width of that image, 600, we get to 2400. So why don't we subtract the width of one image from the total width and that translates to 2400 minus 600 equals 1800. Let's try that. Next, previous, click it again and there we go. Now it's working. Let's go one more time through the set. Good. But what if we go forward, once we get to the last image in a set, when I click next, it should bring us back to number 1, and it does. And we can simply scroll through these images infinitely. And the big advantage to this is because we have not hard coded six hundred in, we've added comments here for you, but we haven't hard coded anything in and I'll leave that on there for your review. But if we come back to index.html and I simply copy this and paste it in. No matter how many images we have, our little slider code is still going to work because we are fetching these widths and lengths dynamically. So, let's try it. Now we have eight images. And we'll simply scroll through one, two, three, four. One, two, three, four, and then it'll reset. Two, three, four. Now we're on image five, six, seven, eight and when I click on it again, it'll scroll all the way back through those seven to the very first one in the bunch. And if I click previous, it'll scroll to the very last item in that set. So this is easily the most complex lesson that we've done so far. And there's somethings I want you to pay attention to. What we've come up with here is just fine, but it doesn't scale overly well. And, that's okay. When you have small sliders like this, there's nothing wrong with keeping it exactly like it is. In fact, it's probably advantageous because you don't need to make code more complex than it needs to be. We're dealing with a simple slider here. This will work just fine. But in the next lesson, I'm gonna show you a slightly more sophisticated way to go about structuring your code.

Back to the top