Jquery Fadein | Find Jquery Examples (Best Tutorial 2019)

Jquery Fadein and Find with Jquery Examples

Basics of jQuery with Examples

jQuery is a powerful and complex library that was first released in August 2006. This demonstrated a new idea that would eventually form the beginnings of the library we know and love today.

 

jQuery was officially announced at Bar Camp NYC in January 2006 and it quickly took the Internet by storm, topping the front pages of many popular sites.

 

jQuery grew and grew, and hit stable v1 in August 2006. From there it has continued to grow. Its impact on web development cannot be underestimated, and its impact on the community view of JavaScript is even more important.

 

In this blog, you will do the following:

  • Look at how browsers represent web pages through the Document Object Model (DOM).
  • Look at DOM nodes and the terms parent, child, and sibling in the context of a web page.
  • Download the jQuery source and include it in a web page.

 

  • Write some code that utilizes jQuery and Jquery Fadein and Find with Jquery Examples.
  • Explore in detail how that code works, and meet some of jQuery’s features.
  • Explore the jQuery API documentation and how to use it to answer any issues you might have.

 

jQuery made JavaScript more accessible to the “average” developer. For example, which of the following two syntaxes do you prefer for selecting an element by its ID?

document.getElementById("example");or

$("#example");

 

Suddenly, if you knew how to select elements with CSS, you could transfer that knowledge to JavaScript by using jQuery. jQuery provided a reliable cross-browser method of interacting with the Document Object Model. Before we get much further, it’s time to discuss the DOM.

 

The Document Object Model (DOM)

The Document Object Model (DOM)

When you look at a website, you see a lot of elements grouped together and styled to form what’s in front of you. To be able to access those elements through code to remove, add, and manipulate them, you need some form of interface—a representation of the elements on a page that is structured and follows a set of rules on how to model them.

 

This is what the DOM is. The DOM also lets you capture browser events—such as a user clicking a link, submitting a form, or scrolling down the page. 

 

In the early days of the Web and browsers, standards in terms of JavaScript implementation were not very clear. This led to browsers implementing features in different ways, which caused developers issues.

 

It led to any JavaScript having to effectively be written multiple times for the different browsers that had different implementations—primarily Netscape and Internet Explorer (IE).

 

Thankfully, as things progressed, browsers adopted the same standards and things settled down. However, the level at which browsers support the DOM can still cause issues today. In particular, we’re not free of the older versions of Internet Explorer, which do not support the DOM to the level of more-modern browsers.

 

This is one reason jQuery is so valuable: everything it offers works just as well in an older version of IE as it does in the latest release of Google Chrome or Mozilla Firefox. It is important to note that the last version of IE is 11; Microsoft Edge is now the default browser in Windows 10.

 

Before continuing with jQuery (you’ll get there soon!), it’s worth taking a moment to introduce how the DOM works. When a page is loaded, the browser generates a representation of what’s on the page, and for each element, it generates one or more nodes that represent it.

 

There are multiple types of nodes, and were this a blog purely on DOM interaction with JavaScript, we’d be covering the DOM in more detail.

 

As we mentioned in the first blog, we feel it’s very important to give people new to jQuery a solid introduction to the foundations on which jQuery is built.

 

We’ve already covered JavaScript in great detail, and we feel it’s important to look at the DOM. When a browser forms a representation of the current page as the DOM, every element is a node. Let’s say you have a paragraph with some text in it, such as:

<p>Hello World</p>

 

That’s not one node, but two nodes. There’s a text node that contains “Hello World” and an element node that’s the paragraph.

 

Note The text node would be a child of the element node because it resides within it. In a typical page, there are a lot of nested nodes.

A p with two paragraphs that both have text within them is structured like so:

  • p element node
  • paragraph element node
  • text node
  • paragraph element node
  • text node

 

The two paragraphs in this instance are siblings because they have the same parent node. The paragraphs are children of the p, but the text nodes are not child nodes because they are not direct descendants of the p element.

 

They are child nodes of the paragraph nodes. There are three main types of nodes that you need to know: element, text, and attribute nodes. Let’s say that you gave the paragraph a class, such as:

 

<p class="intro">Hello World</p>

There are now three nodes at play:

  • The element node representing your paragraph
  • A text node that contains the text “Hello World”
  • An attribute node that states this element has class="intro"

 

Somewhat confusingly, an attribute node is not considered to be a child of an element node. Between those elements, they make up the vast majority of most of the web pages out there. Before

 

(finally) getting to jQuery, make certain that you understand the following terms because they are used continually throughout the blog:

  • child node: A node that is a direct descendant of another node, usually an element node
  • parent node: A node that has direct descendants (e.g., children)
  • siblings: Two nodes that share the same parent

 

And just to iterate one final time, the following is a visual representation:

p parent
p child of p, sibling of p
 "hello world" - child of p
 p child of p, sibling of p
strong child of p
 "hello" child of strong

 

Understanding the terms “child,” “parent,” and “siblings” will be very important later in the blog when we discuss selecting elements with jQuery, so make sure you’re confident about their meanings.

 

Downloading jQuery

Downloading jQuery

After a lot of preparation, you are ready to pe into jQuery and use it for the first time. The best place to start is the jQuery web site at jQuery

 

Click the large Download jQuery button (or the Download tab) on the jQuery home page to open to the Download page. Here you are given instructions on the many ways you can add jQuery to a project. For example, if you want to add jQuery locally, you can download either the compressed version or the uncompressed version.

 

If you are using npm (Node Package Manager) or Bower (another package manager), you can find the instructions here. In addition, there are instructions for using a CDN (content delivery network) and for a few other ways.

 

If you click the “Download jQuery” button on the home page. You are presented with multiple options to download jQuery. There are two compression-level options listed on the download page:

  • Production (87KB), Minified and Gzipped
  • Development (268KB), Uncompressed Code

 

Unless you want to study the jQuery source in detail for every project that you create using jQuery, always pick the Production version. This code has been run through a minifier, a program that compresses JavaScript files into smaller versions. Minifiers perform a number of actions to get the code down to as small as possible, including

  • Stripping out all white space.
  • Removing all comments.
  • Renaming long variable names; for example, var myCar might become var a.

 

Minified code is completely unreadable, but it’s not designed to be readable—it’s designed to make the file as small as possible. From now on when we refer to the jQuery source, we’re referring to the minified version of jQuery.

 

Some developers link to a CDN-hosted version of jQuery, the most popular of which is Google’s CDN (Hosted Libraries | Hosted Libraries| Google Developers). These allow you to include jQuery by referencing the jQuery file that’s hosted on their CDN. If you wanted to include the latest version of jQuery from Google’s CDN, you’d do it like so:

 

<script class='lazy' data-src="http://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

 

Doing it this way brings advantages. If the user has visited another site that references jQuery in this way, they may have the file cached already, meaning the browser does not have to download it again.

 

For examples in this blog, however, we’ve chosen to download a version of jQuery locally for one simple reason: you don’t need the Internet to work through the examples.

 

It may sound foolish, but more than once, one of our authors has been ready to do some work while on a train, only to remember he referenced the Google CDN version of jQuery, and he didn’t have an Internet connection.

 

The jQuery API Documentation

The jQuery API Documentation

If you are using jQuery, you need a good source from which to learn what each API does. The jQuery documentation (jQuery API Documentation) lists every method jQuery provides. Another reason jQuery has become so successful is its documentation, which is fantastic. We seriously cannot overstate how good we think the documentation is .

 

There are a couple of ways to find what you’re looking for on the web site. If you know exactly which method you want, using the search box located at the top right of the screen is by far the quickest way. 

 

If you’re not certain about exactly what you want—perhaps you’re looking for a method to do something particular, but you’re not sure if it exists—you can browse the jQuery API categories listed on the left side of the screen to narrow your search.

 

You don’t need to look at these yet, but you will return to the API many times. Put it on your blogmarks bar, or find an easy way to browse it, as you will use it a lot.

 

Writing Some jQuery

Writing Some jQuery

Save your downloaded jQuery file as jquery.js in a new folder on your machine. You’re also going to add an HTML file to this folder, so create an index.html page, too. Finally, you want to write all the JavaScript in an inpidual file, so create app.js. This code is available within 02/code/ex1.

 

Load the HTML page in your editor of choice—I personally use Vim we highly recommend Sublime Text 2 (Sublime Text 2 - Sublime Text), Visual Studio Code (Visual Studio Code - Code Editing. Redefined), or Atom (A hackable text editor for the 21st Century), all of which run on Windows, macOS, and Linux—and add the following:

<!DOCTYPE html>
<html>
<head>
<title>blog 02, Exercise 01</title>
<script class='lazy' data-src=jquery.js></script>
<script class='lazy' data-src=app.js></script>
</head>
<body>
<p>Hello World</p>
</body>
</html>
This is just a basic HTML page, nothing fancy. Take a look at the two <script>tags<script class='lazy' data-src="jquery.js"></script>
<script class='lazy' data-src=app.js></script>

 

First, load in jQuery and then load in the app.js file, which is currently blank.

Note The order of the files being loaded with the script tag is very important. Remember that the code you write is going to be dependent on jQuery, so you have to load jQuery before any scripts that use it.

 

Now that you have your page, go ahead and load index.html in your browser. You won’t see anything yet, other than the “Hello World” text. Go into app.js and add the following line—the first line of jQuery you’ve written in the blog!

$("body").css("background", "red");

 

Can you guess what that does? You have already seen that $("body") selects the "body" tag (remember, they are just CSS selectors), and you can probably take a logical stab at what css("background", "red") does. Refresh the page, and you … won’t see any change.

 

This is a mistake that many jQuery beginners make when starting out. The problem is back in your index.html file:

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>blog 02, Exercise 01</title>
<script class='lazy' data-src=jquery.js></script>
<script class='lazy' data-src=app.js></script>
</head>
<body>
<p>Hello World</p>
</body>
</html>

Load in your JavaScript before you load in the rest of the page, so when your JavaScript is executed, the page hasn’t fully loaded, which means the DOM is not ready.

 

Because the page isn’t fully loaded at the time your JavaScript is run, the browser hasn’t completed constructing the DOM, which means as far as the DOM is concerned, "body" doesn’t exist when your JavaScript runs. You have two options here:

Include your JavaScript at the bottom of the page, just before the closing </body>. This means it’s run after the DOM is loaded.

Tell your JavaScript not to execute until the DOM is ready.

 

In practice, it’s better to include JavaScript at the bottom so that it doesn’t delay the content loading. So for most of this blog, we’ll be doing that.

 

This time, however, we’re going to choose the second option— purely because we need to explain how you go about doing it. In order to discuss how to stop your code from running until the DOM has loaded, we are going to talk briefly about events. 

 

Within the browser, writing JavaScript is very much event based. Write code that’s executed based on an event. The user clicks a button, scrolls down the page, hovers over an image, and so on. Each of these actions causes an event to fire, which is grabbed by JavaScript, and then the code is executed based on that event occurring.

 

The browser also emits an event when the DOM is loaded. You can then write code that is only executed when that event fires, meaning you know your code will only be executed when the DOM is all set and ready to rock. With jQuery, you do it like so:

$(function() {

//DOM is ready to go

});

Let’s break down this line:

 

$(document): This passes the document variable into jQuery. The document variable is a special variable that contains references to all the HTML elements on the page. When this object fires a ready event, you want to execute some code.

 

.ready(): ready is one of the many events jQuery supports. You pass into it a function that is executed when the ready event is fired. Because you’re doing $(document).ready(), the function you pass in is fired when a ready event is registered on the document object.

 

function() {}: What you pass into the ready call is a regular JavaScript function, which will then be called when the event is emitted. This is like creating functions, as you did in blog 1, but instead of naming them, you just pass one straight in. You could do it like so:

function onReady() {

alert("READY TO GO!");

}

$(document).ready(onReady);

But in practice, it’s easier just to create the function and pass it immediately into the event handler without explicitly naming it first. By doing this, you create an anonymous function, a function that doesn’t have a name.

 

The preceding line represents all of the following:

$(function() {
$("body").css("background", "red");
});
When you refresh index.html, you’ll see a red background! Now, doing $(document).
ready(function() {}) is so common, jQuery has a handy shortcut. You can simply do the following:
$(function() {
});

 

And that means exactly the same thing. If jQuery detects you’ve passed it a function, it will presume that function should be executed on the DOM already. It’s a handy little shortcut to save you a small amount of typing.

 

The phrase “jQuery detects you’ve passed it a function” in the preceding paragraph means that when you’re selecting something like $("body");, what you’re actually doing is calling a function that jQuery provides, which is stored as a variable called the $ symbol. You could easily do this, too.

 

The following code is valid because JavaScript doesn’t mind variables having the $ symbol in them or variable names being just one character long:

var $ = function() { console.log("hey"); };

$(); //logs "hey" to the console

 

Note Don’t do the preceding if you’ve got jQuery on the page, because you’ll overwrite the $ variable— meaning it won’t reference jQuery anymore. So all jQuery does is have a function bound to $, which is clever.

 

It can detect what you pass into it, and do certain things. So when you pass in $("body");, it knows to select the body element. But when you pass in $(function() {});,it detects you passed in a function, and acts accordingly.

 

Now, try something a bit more complicated. In the <head> of your HTML page, add a link to a new style sheet, which you should also create, as follows:

<link rel="stylesheet" type="text/css" href="style.css" />
Get rid of your Hello World paragraph, and replace it with the following HTML within the <body> tag:
<p id="box">my box</p>
Head into style.css and add the following:
#box {
width: 100px;
height: 100px;
text-align: center;
background: #f00;
font-size: 14px;
}
Finally, edit your app.js to be simply:
$(function() {
});

 

It’s not going to win any design awards, but now you can do some fun stuff with this box. First, create a variable that will store a reference to the p with the ID "box", as follows:

var box = $("#box");

 

Save the reference to it as a variable because you’re going to use it more than once. Doing the following is inefficient because you’re making jQuery select the element twice every time you use $("#box"):

$("#box").doSomething();

$("#box").doSomethingElse();

It is much better to do it once and save it to a variable.

 

Animation Example

Animation Example

Now let’s look at a jQuery animation example. While animation might seem a daunting prospect, particularly to start with, it’s one of the areas that really shows off jQuery’s power and gives immediate results, which makes it a good place to start.

 

This example won’t go into too much detail, just skim over a few of jQuery’s key features. You’ll look at each of the areas in great detail later. This is purely a relaxed introduction to jQuery’s capabilities.

 

The first thing you’re going to do is fade your box out. Make your app.js file look as follows:

$(function() {

var box = $("#box");

box.fadeOut("slow");

});

 

Refresh your page—and that lovely red box will slowly fade out of view. It’s probably easy to see why the fadeOut() method is aptly named. As you can see, passing in the argument "slow" makes the box fade out slower. You can also use the keywords "normal" and "fast", which do exactly what you’d imagine.

 

If you want a page that gives you a comprehensive overview of how the fadeOut method works and how to use it, look to the jQuery API documentation. If you search for fadeOut and make your way to the documentation for the method.

 

The first bit of the documentation is as follows:

.fadeOut( [duration] [, complete] )

duration A string or number determining how long the animation will run.

complete A function to call once the animation is complete.

 

Being able to read and make sense of the API will save you a lot of time. The preceding syntax may be alien right now, but once you know how it works, it’s easy to follow because it’s consistent throughout the API.

 

The first line describes how the method can be called. This shows that you can call fadeOut() by passing in a duration and a completion function.

 

The square brackets around each argument means the argument is optional—you don’t have to pass either in. You can pass one argument in, pass both in, or none, and jQuery knows how to handle that. Earlier, you called it as follows: $("#box").fadeOut("slow");

 

You can see that you passed in the duration, but not a completion method. Callback is a term used often in JavaScript that refers to a function that is called once something has finished executing.

 

In the contextof fadeOut(), this completion function will be called after your box has faded out. To see this in action, change your app.js to the following:

$(function() {

var box = $("#box");

box.fadeOut("slow", function() {

alert("box finished fading out");

});

});

 

Once the box is faded out, you will see an alert on your screen. This gives you great power to be able to do something, and then run something else the moment that original thing is finished. Callbacks are used extensively in jQuery.

 

A vast number of methods, especially animation ones, take callbacks, and you will use them frequently. Of course, because both parameters are optional, you can also pass in just a callback, like so:

$(function() {

var box = $("#box");

box.fadeOut(function() {

alert("box finished fading out");

});

});

 

You’ll notice this time when you refresh, the box fades out more quickly. Previously, you were passing in a "slow" speed. But what happens when you don’t pass in one? What does jQuery do?

Any argument that is optional also has a default value, and the jQuery API will always tell you what it is.

 

In the case of fadeOut(), the jQuery API says:

Durations are given in milliseconds; higher values indicate slower animations, not faster ones. The strings 'fast' and 'slow' can be supplied to indicate durations of 200 and 600 milliseconds, respectively.

 

If any other string is supplied, or if the duration parameter is omitted, the default duration of 400 milliseconds is used. (jQuery API Documentation fadeOut/)

 

So if you miss out a parameter, it defaults to 400 milliseconds. Passing in "slow" was setting it to 600 milliseconds. You can also pass in a number, too. Try making it really slow. Remember, the number is milliseconds, so 3 seconds = 3000 milliseconds.

$(function() {
var box = $("#box");
box.fadeOut(3000, function() {
alert("box finished fading out");
});
});
So with fadeOut(), jQuery has the three default strings that it recognizes:
"slow": 600 milliseconds
"normal": 400 milliseconds (it also the default)
"fast": 200 milliseconds
Other than that, you could pass in a value in milliseconds.

 

Now say you wanted to fade a box in and out continuously, maybe ten times. You’ll not be surprised to learn that fadeOut() has a companion, fadeIn(), which does the exact opposite. Therefore, you can combine these two methods to get the desired effect. At least, that’s what you’d do if you didn’t look through the API properly.

 

You see, along with fadeIn() and fadeOut(), there’s also fadeToggle(). This will fade in a box if it’s not visible, and fade out a box if it is visible. Thus, you can use this to make things much easier.

 

If you searched the documentation for “fade”, then you have seen this method. We can’t encourage you enough, especially when learning, to use the API documentation extensively.

 

So, here’s what you will do:

\1.\ Create a function that will toggle the box in and then out.

\2.\ Store a variable that keeps count of the number of times you’ve done this.

\3.\ Have a paragraph that always has its text updated to be the number of times the box has faded in and out.

 

The function will then call itself, making the box fade in and out once more—if the variable that keeps count is less than a certain amount. There will be a few new things here, so be patient.

 

By the end, you will have seen how easy jQuery makes things, which is very exciting. You are continuing from where you left off with the prior exercise, so you are not starting completely afresh.

 

The first thing to do is add the paragraph to your index.html page, which should look as follows:

 <!DOCTYPE html>
<html>
<head>
<title>blog</title>
<script class='lazy' data-src=jquery.js></script>
<script class='lazy' data-src=app.js></script>
<link rel=stylesheet type=text/css href=style.css />
</head>
<body>
<p id=box>my box</p>
<p></p>
</body>
</html>

 

Adding an empty HTML element is not good practice, but you will learn how to learn how to avoid that problem in the near future. Edit app.js, and set up the variables you’re going to use, as follows:

$(function() {

var box = $("#box");

var para = $("p");

var i = 0;

});

 

You’ll store a reference to the box, the paragraph, and the count variable i, which you set to 0. The first thing to do is make your paragraph show the value of the counter. To update the text within an element, you can use the text() method.

 

If you call text() with no parameters, that will give you back the text. If you pass in a parameter, it will set the text to be what you pass in. Therefore, you can do para.text(i); to set the text to have the value of i.

 

Now you have to write the main function to perform all the toggling. Rather than do this line by line, it’s easier just to look at the complete code and then walk through it. Your app.js file will look like so:

$(function() {
var box = $("#box");
var para = $("p");
var i = 0;
para.text(i);
function toggleBox(i) {
box.fadeToggle(500, function() {
i = i + 1;
if(i < 10) {
para.text(i);
toggleBox(i);
};
});
};
toggleBox(i);
});
Let’s talk about the toggleBox() function:
function toggleBox(i) {
box.fadeToggle(500, function() {
i = i++;
if(i < 10) {
para.text(i);
toggleBox(i);
};
});
};

 

The first thing you do is call fadeToggle(), which will fade the box in or out, depending on its current state. Just like fadeIn() and fadeOut(), give it a speed—half a second (500 in milliseconds)—and a callback function, which is executed once the box has been faded in/out.

 

The function takes an argument, the i variable, which stores the number of fades that have been performed. You need this to see if you should continue fading or not.

 

Within the callback, do the following:

Increment the value of i by 1-, the ++ operator is used, which is a shortcut

for i = i + 1.

If i < 10:

Set the value of the paragraph to be the current value of i.

Call toggleBox() again, passing in i.

 

And with that, you can refresh your page and see a box that will fade in and out five times before stopping. You’ll also see the paragraph show the number of times it happened.

 

But hang on. Why does it show 9, and not 10? It has, in fact, faded in and out ten times. The reason is that i is initially set to 0, so the first time the box fades, it actually is the zero-th time it’s faded. Hence, when i is 9, it’s actually happened ten times.

 

It’s common practice to make count variables start at 0, primarily due to arrays being zero-indexed, as you saw in blog 1. However, you might want to make the value outputted go from 1 to 10, which is easily done by changing both lines that say

para.text(i);

to

para.text(i+1);

Thus, 1–10 will display in the browser, but behind the scenes, it’s using 0–9.

 

Traversing the DOM

You’ve seen how jQuery works and how to make animated boxes fade in and out. Now it’s time to take a more methodical look at the library and explore everything it can do. This blog doesn’t cover every method jQuery has to offer because a lot of methods do very similar things. There are also methods that do the exact opposite of each other.

 

After looking at how fadeOut() works, you looked only briefly at fadeIn() because it was obvious what it would do, having met fadeOut(). There is a similar situation with a lot of jQuery methods.

 

This blog won’t simply be a documentation of all jQuery’s traversal methods, however. Efficiency is a large part of this blog—and it will be mentioned a lot. Here’s what this blog holds:

  • Selecting elements with CSS selectors and exploring which are the most efficient.
  • Using jQuery pseudo-selectors.
  • Exploring the variety of traversal methods that jQuery provides.
  • Caching selectors and chaining methods to avoid reselecting elements.
  • Avoiding more DOM work than necessary. The bottleneck of any jQuery project is always the DOM interaction. Interacting with the DOM is expensive, so the fewer times you can do it, the better.

 

CSS Selectors in jQuery

css

 

The beauty of jQuery, and why it became so popular, certainly involves the fact that it’s so easy to use. You’re probably familiar with CSS, and you know that to select an element by its ID, you use the hash symbol (#).

 

To select an element by its class, you use a period (.), and so on. jQuery lets you use these selectors (and more) to select elements from the DOM. What’s also great is that it provides backward compatibility. So even if the CSS selector you use doesn’t work in IE7 and below, it will work when you use it in jQuery.

 

However, with great power comes great responsibility, and a lot of these selectors are highly inefficient from a computational viewpoint. The most basic way to select an element is by its ID, as follows:

$("#header");

$("#maincontent");

This way is always going to be quicker than selecting by a class or by a tag name, the other common ways; for example:

$(".column");

$(".header");

$("body");

$("p");

 

The reason selecting by an ID is the best way is two fold. First, JavaScript has its own mechanism for selecting by ID—document.getElementById("header")—so when jQuery detects that you’ve passed in an ID, it can simply call that method. Second, there should only ever be one element with any specific ID, so once it’s found a result, it stops searching.

 

Note It’s up to you to ensure that there’s only ever one instance of an ID on a page. If you do have more than one element with the same ID, JavaScript (and hence, jQuery) will only return the first one. It’s invalid HTML to have an ID exist on more than one element.

 

If you’re looking for something by a class, there could be multiple results, so JavaScript has to keep searching the entire DOM. If you can select an element by an ID, do so.

 

Another thing worth mentioning is the way jQuery deals with results of a selector. Results will return an array-like structure (it’s not actually an array, but acts like one, as described in more detail shortly) regardless of whether one element is returned or fifty elements are returned. Let’s say that you’ve got one paragraph on a page and you run $("p"). Take a look at what you get back:

[<p>Hey</p>]

If you’ve got a few more, you get this:

[<p>Hey</p>, <p>Hey</p>, <p>Hey</p>, <p>Hey</p>]

 

Note If you’re using a browser other than Google Chrome, your output may be slightly different.

The preceding example shows the output from the Chrome browser developer tools. For example, in Firefox, the output is

[p, p, p]

 

Rest assured, the code is finding the same set of elements. It’s just that the consoles output them differently.

One of the nice things about this is that you can then easily find out the number of items returned by using .length on the result, as follows, because the result acts just like a JavaScript array:

$("p").length; // 4

 

You can use the jQuery method $("p").size() in versions of jQuery before 1.8, but all that .size() does is return the result of using .length, so developers typically use .length.

At this stage, it might look like jQuery just returns a regular array, but it doesn’t. It returns a jQuery object. This jQuery object is just like the regular objects.

 

It contains all the jQuery properties and methods alongside the elements from the selector you performed. A good way to think of it is that the jQuery object is an enhanced array.

 

At its core, it has a list of DOM elements—but it is much more than that. Remember that when you run $("p") and get back what looks very much like an array, it’s not. It’s actually a jQuery object.

 

One of the things new users of jQuery find most confusing is the way some methods get called on every element they return, and others don’t. For example, let’s say you’ve got a list of four paragraphs and you want to give each one a class. The following will work:

 

$("p").addClass("paragraph");

The addClass() method is pretty self-explanatory. It simply adds a class to the elements. Notice here that this addClass() method is run on every element in the result set.

 

Also notice that you do not have to loop over them. If you’ve got a set of elements and call a method, more often than not, jQuery will implicitly do the looping for you. This is really useful, but it can be a bit confusing, so just remember that jQuery will always loop for you if it can.

 

Of course, because jQuery can parse CSS selectors, you can pass it very complicated selectors, such as:

$("p>ul a");

$("p#main p strong");

$("p.main p>li a");

 

But the downside of those selectors is that the more complex they are, the more time they take to run, and the slower your code will execute. jQuery parses its CSS selectors from right to left, so what that last example does is

  • Locates all anchor elements.
  • Filters out those anchor elements not within a list item.
  • Filters out all remaining elements so that the ones left are within an <li> that’s an immediate child of a paragraph.
  • Selects only the remaining elements that are within a class of main.
  •  Selects only those remaining that are within a p with that class of main.

That is a lot of work just to find some links. It’s this kind of thing that you need to be wary of and keep in mind when deciding which selector to use.

 

Traversal Methods

Traversal Methods

Traversal methods are methods that let us “jump” around the DOM to find specific elements. A traversal method will help you get from element A to element B through a number of ways.

 

In this section, you’ll investigate what those methods are and explore how to be as efficient as possible. jQuery has a large number of traversal methods, as the documentation (jQuery API Documentation) will show you.

 

For the rest of this blog, we will go through the methods that we consider the most useful—and the ones you will use the most. There will be various tangents along the way to further discuss things that you need to know.

 

You will often have a set of elements that you want to narrow down. Perhaps you only want the first one, or the last, or perhaps you’d like a specific one from the array. You can use the eq() method to do this. Let’s say that your HTML contains some paragraphs, like the following:

<p>Para 1</p>

<p>Para 2</p>

<p>Para 3</p>

Then let’s say that you ran $("p"). You would get the following result:

[<p>Para 1</p>, <p>Para 2</p>, <p>Para 3</p>]

 

The eq() method will give back a jQuery object containing the element at a specific index. For example, $("p").eq(0) will give you the jQuery object containing your first paragraph (remember, arrays are zero-indexed). Let’s say you were to run the following:

alert($("p").eq(0).text());

 

You’d see Para 1 because getting the first element is such a common thing to do that jQuery provides first(), which does exactly the same. It won’t surprise you to learn that there’s also a last() method.

 

Because getting the first result is so common, jQuery gives us another way of doing things. Consider the following:

$("p:first");

$("p:eq(0)");

These would both achieve the same effect. jQuery has support for a number of these pseudo-classes.

Note jQuery supports most CSS pseudo-classes but also has a number of its own, such as :eq(0). You can find more information about pseudo-classes at: CSS: Cascading Style Sheets

 

Pseudo-classes

Some pseudo-classes directly match CSS3 specification, but others (including the preceding two) do not. In the course of this blog and this blog, you will see a lot of them.

 

The question now becomes which one to use when jQuery offers both a pseudo-class selector and a method. We much prefer using a method to a pseudo-selector. We think they read much better and it’s easier to see what’s going on.

 

This is due to the fact that when you use the method, it’s not contained within the selector. This means when you’re scanning through the code, the call to the method stands out more because it’s not within the selector.

 

There’s also another reason, though. Newer, more modern browsers such as Google Chrome and Mozilla Firefox support two methods that are very powerful: querySelector() and querySelectorAll().

 

These are powerful selection methods that can parse any CSS selector. querySelector() returns the first match for the selector, and querySelectorAll() returns all matches.

 

jQuery will always use querySelector() and querySelectorAll() if they are available, because doing so is much quicker at getting elements with complex selectors.

 

If you use the $("p:first") selector, jQuery can’t simply pass "p:first" to the querySelectorAll() method because ":first" is not a CSS pseudo-class. However, if you use $("p").first(), jQuery can pass the "p" selector to a native JavaScript method—getElementsByTagName() in this instance—and then call first() on the result of $("p").

 

Any native method is always going to be quickest, and so whenever you have the option to allow jQuery to use native methods, you should do so.

 

Further Traversal

Once you’ve got your initial set of elements, there’s a high likelihood you’re going to want to further search within them. Take the following HTML structure:

<p>

<p>Paragraph <strong>one</strong></p>

<p>Paragraph Two</p>

</p>

Let’s say that you’ve first selected the <p>, and then saved that to a variable (also known as caching):

var myp = $("p");

Now let’s say that you want to find all paragraphs in that <p>. jQuery offers two ways of doing this:

myp.find("p");

myp.children("p");

Or, of course, you could have originally written

$("p p");

 

Taking these three methods into account, which one is best? If you’re going on speed alone, $("p p") will always be quickest by far in newer browsers—that is, those that support querySelector() and querySelectorAll().

 

If you’re building a site for only these browsers, it’s actually more efficient to do most of your filtering in your initial selection, so you use querySelectorAll().

 

If you are worrying about older and newer browsers alike, then $("p p") is often the slowest method, particularly if your selectors are more complex. That leaves two methods: find() and children().

 

There’s an important difference between these two methods. The API describes them at jQuery API Documentation category/traversing/ children() is described as “Get the children of each element in the set of matched elements, optionally filtered by a selector.” find() is described as “Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.”

 

The key difference is in the third word of each description. The first method will get the children of each element, and the second method gets the descendants.

 

Here, the paragraphs are children of the p. However the paragraphs, the <strong>, and the anchor are all descendants of the p. Children are direct descendants only, whereas descendants means everything within that element, regardless of what level it’s on.

In this situation, examine the following structure:

<p>

<p>Paragraph <strong>one</strong></p>

<p>Paragraph Two</p>

</p>

 

You should use children(), not find. The reason is that find() will search every level of the DOM to try and find a match, whereas children() will only search the immediate level of the element to find a match. So, when you only want immediate descendants, as in the example, children() is going to be quicker.

 

Admittedly, it’s a marginal speed difference, but it’s only going to do what you need it to do—whereas find would do much more—so it makes sense to stick to children(). It also shows that you’re only selecting immediate descendants, making your code read better.

 

With the two methods, children() and find(), you’re not limited to passing in a tag. They, along with all traversal methods akin to them, take any CSS selector, just like the ones you might pass in to the initial jQuery object through $(), such as:

$("p").find("p>strong");

This will return all strong elements that are direct children of paragraphs, where those paragraphs exist within a p.

 

Another very useful method is siblings(), which gets all the siblings of the current element, as you might expect. Take this structure:

<p>

<p class="first-paragraph">Paragraph 1</p>

<p>Paragraph 2</p>

<p>Paragraph <strong>3</strong></p>

</p>

 

Running $("p").siblings() will give you no results. This is because the <p> is the only element at that level. To get all the siblings of the first paragraph, you could do the following: $(".first-paragraph").siblings();

 

This would give a result set containing the other two paragraphs, but not the initial paragraph. If you wanted to add the initial paragraph to the set of elements so that you have both the element’s siblings and the original element, you could use .add(), which can be used to add other elements to an existing set. For example, consider using the following: $(".main").add(".paragraphs");

 

It would leave you with a result set of elements with a class of "main" and also those with a class of "paragraphs". So in the example, you could do the following: $(".first-paragraph").siblings().add(".first-paragraph");

 

But this isn’t very efficient. Notice that you’re running the selector twice. This means that you’re searching the DOM twice, which is not good at all. Thankfully, jQuery provides andSelf(), which is an easier way to do this. It takes the set of elements from the previous selection and adds it to the current selection: $(".first-paragraph").siblings().andSelf();

 

This gives a set that includes the siblings() and the initial paragraph. andSelf() is not a method you will find yourself using that frequently, but it’s a very useful one to know. With your DOM structure, there’s actually another way you can get the siblings of the first paragraph:

$(".first-paragraph").nextAll();

nextAll() gets all the siblings that are after the current element. So, with this HTML, it is as follows:

<p>

<p>Paragraph 1</p>

<p class="second">Paragraph 2</p>

<p>Paragraph 3</p>

</p>

Running $(".second").nextAll(); gives just one element back—the third paragraph. Running $(".second").siblings() gives two elements—the first paragraph and the last.

 

So nextAll() gets all siblings that are after the current element in the DOM structure. There’s also the opposite method, prevAll(), which gets all siblings before the current element.

 

You’ve also got prev() and next(), which get the sibling next to the current element—either the one before the current element in the case of prev(), or the one after the current element in the case of next().

 

Chaining Methods

Chaining Methods

You may have noticed that the preceding example chained two methods together, like so

$(".first-paragraph").siblings().andSelf();

 

This is one of jQuery’s key features. Methods can be called one after another and be chained together. Any methods that return a jQuery object can be chained. To tell if a method returns the jQuery object, check the top-right corner of its jQuery API documentation.

 

There are methods that either can be chained or cannot be chained, depending on how they are used. One such method is text(). If you call text() with no arguments, it will return the text of the element.

 

However, if you pass it some text, it will set the text of that element, and will then return a jQuery object. The documentation for text() shows this. There are two different entries.

 

  • The first is for text() on its own, which returns the text. You can see that the documentation denotes that it returns a string
  • Then there’s text(), which takes an argument and sets the text. It does return the jQuery object
  • The general rule of thumb is that any method that doesn’t explicitly return something other than a set of elements can be chained.

Chaining is a good way to avoid selecting elements more than once, as follows:

$("p").fadeOut();

$("p").css("color", "red");
$("p").text("hello world");
Instead of doing that and running $("p") three times, you could do this:
$("p").fadeOut().css("color", "red").text("hello world");
White space isn’t important here, so if you want to split these onto multiple lines, feel free. We often do it like so:
$("p")
.fadeOut()
.css("color", "red")
.text("hello world");

 

Just be careful that you don’t miss any dots between methods, and remember that the semicolon only goes at the end. If you’re not into chaining, you might prefer to cache the selection, as you’ve already seen:

var p = $("p");

p.fadeOut();

p.css("color", "red");

p.text("hello world");

 

So far, you’ve used children() and find() to traverse further down the DOM structure, but of course there are also functions for doing the exact opposite. These are called parent() and parents().

 

The key difference between the two is that parent() goes only one level up the DOM, whereas parents() goes all the way up. You can find the definitions for these functions (as with all) on the jQuery site.

 

parents() quite literally gets all an element’s parents, right up to the very top element. Take the following HTML structure:

<p>
<p><strong>Hello</strong></p>
</p>
The result of $("strong").parents() is
[<p>...</p>, <p>...</p>, <body>...</body>,<html>...</html>]
The result of $("strong").parent() is
[<p>...</p>]

 

Because parents() traverses the entire DOM, you’ll nearly always want to pass it some selector, simply because it’s rarely ever useful for .parents() to give back the body and html elements. However, sometimes you may want all the parents up to the body element, so something you often need to do is filter out the set of elements that parents() returns.

 

There are two ways of doing this. The first is to use jQuery filters. Earlier you used the :eq selector and the .eq() method to filter your results down to one result. That is one of jQuery’s filtering methods, which are all documented in the API (jQuery API Documentation).

 

The method that interests us right now is not(). We will also cover the rest—some in this blog and some elsewhere in the blog. not() does exactly what you’d expect—it filters results. If you want to remove the body and html elements from your parents() call, it’s as easy as this:

$("strong").parents().not("html, body");

 

This takes all the parents and filters out the html and body tags. This works because not() takes a CSS selector. You are effectively telling jQuery to filter out elements that match the CSS selector "html, body". And of course, this selector matches the html and body elements.

 

You can also use the pseudo-class :not, much like you could use :eq, but as explained earlier, using the method is preferable to the pseudo-class (and it’s easier to read), so that’s while you’ll see for the rest of this blog.

 

There is, however, a much better way to do what you want, and that’s to use parentsUntil(). With parentsUntil(), your code is much simpler. Remember, parentsUntil() gets all elements up to but not including the one your selector matches. Now that you know of this method, all you have to do is the following:

 

$("strong").parentsUntil("body");

This gives the desired result. It is a strong trend with jQuery. If something seems a bit long-winded, there’s a high chance that there’s an easier way to do it.

 

Two filters that are very useful are the :even and :odd filters. Combining them with the filter() method, which takes a filter and returns the ones that pass, you can easily apply background colors to rows to make the table appear striped. Here’s a simple table to use:

<!DOCTYPE html>
<html>
<head>
<title>blog 03, Exercise 01</title>
<script class='lazy' data-src=jquery.js></script>
<script class='lazy' data-src=app.js></script>
<link rel=stylesheet type=text/css href=style.css />
</head>
<body>
<table>
<tr><td>Jack</td><td>Franklin</td></tr>
<tr><td>Stuart</td><td>Robson</td></tr>
<tr><td>Rob</td><td>Hawkes</td></tr>
<tr><td>Alex</td><td>Older</td></tr>
</table>
</body>
</html>
The following just gives the tables some borders to clearly define the rows:
table {
border-collapse: collapse;
}
tr {
border-left: 1px solid grey;
border-right: 1px solid grey;
border-bottom: 1px solid grey;
}
td {
padding: 10px;
}
Here’s the app.js file:
$(function() {
var rows = $("tr");
rows.filter(":even").css("background", "red"); rows.filter(":odd").css("background", "blue");
});

 

The app.js file does three very simple things:

  • Stores the result of $("tr") to a variable, rows.
  • Filters the even rows and colors them red.
  • Filters the odd rows and colors them blue.

 

This is the css() method, but it’s pretty simple. When passed two arguments—a property and a value— it will set the CSS value of the elements in the set. This very simple example shows you the power of jQuery filters.

 

Further Filtering

Further Filtering

If jQuery’s built-in filters are not enough, it also provides a mechanism that allows you to filter by anything you want. You briefly saw the filter() method in action when you filtered for even rows with filter("even"). You can also pass filter() a function that will evaluate each element in a set and return only those that match a certain condition.

 

In your index.html page, add four paragraphs so that it looks like so:

<!DOCTYPE html>
<html>
<head>
<title>blog</title>
<script class='lazy' data-src=jquery.js></script>
<script class='lazy' data-src=app.js></script>
<link rel=stylesheet type=text/css href=style.css />
</head>
<body>
<p><strong>Jack</strong> Franklin</p>
<p><strong>John</strong> Hammelink</p>
<p><strong>Richard</strong> Quick</p>
<p>Will Hammil</p>
</body>
</html>

 

Get rid of everything previously in your style.css; you won’t need any styling.

Now, let’s say that you want to filter for only the paragraphs that have a <strong> tag and give them a red background. The first thing you want to do is get all the paragraphs and store them in a variable, like so:

$(function() {

var ps = $("p");

});

When you pass filter() a function, it expects this function to return true or false. filter() runs once for each element, and will keep elements when the function you pass in evaluates to true. It will get rid of elements that make the function evaluate to false.

 

Within this function, you have access to the current element through the this keyword. The this keyword is a special variable in JavaScript that you can use often to reference the current item you’re working with. To gain access to the current element you’re working with but wrapped in a jQuery object, you can simply run $(this).

 

To filter out all elements without a strong element within, you need to check if the paragraph contains any. There are two bits of information that will get that result:

 

You can get all strong elements within an element through $("p"). children("strong");

You can see how many elements are in the result set by adding .length, like so: $("p").children("strong").length;

So, for a paragraph to contain strong elements, the following must be true:

$("p").children("strong").length > 0;

 

This expression, which can return true or false, is what you’ll pass into your filter function, like so:

$(function() {
var ps = $("p");
var strongPs = ps.filter(function() {
return $(this).children("strong").length > 0; });
strongPs.css("background", "red");
});

 

I’m sure you can imagine that the filter() method, when passed a function, is incredibly powerful. You could filter for absolutely anything that you want, as long as you can evaluate it to true.

 

There’s one way you could simplify the code. The filter() method still returns the jQuery object, which means it can be chained. This means that you can shorten the code a little, as follows:

$(function() {
var ps = $("p");
ps.filter(function() {
return $(this).children("strong").length > 0; }).css("background", "red");
});
Here you are using a ps variable, but only referring to it once; get rid of it so that you’re left with the following:
$(function() {
$("p").filter(function() {
return $(this).children("strong").length > 0; }).css("background", "red");
});

Much better!

 

DOM Manipulation with jQuery

dom

So now you know a fair amount about jQuery and what it can do. You know how to select elements, how to make sure your code only runs after the DOM is loaded, and plenty more.

 

You’ve also taken a look at animations and done some basic manipulation by changing colors of elements using the css() method. What you might not have realized is that animations are manipulation.

 

Previously, you used fadeIn()/fadeOut() to manipulate the opacity of an element over a period of time. This blog will focus entirely on manipulation of elements, including:

  • Changing CSS styles with the css() method
  • More animation as you meet jQuery’s animate() method
  •  Inserting, removing, and moving elements around the DOM
  •  Editing element attributes with attr()
  • A myriad of manipulation methods that jQuery provides

 

On your way through, you’ll take regular pauses and small tangents to examine best practices. DOM manipulation is often a huge bottleneck in web sites, so you should try to do it as little as possible. There are many tricks and ways to limit the time spent on the DOM, and we’ll mention these as you go through the blog.

 

CSS

CSS

jQuery’s css() method is very powerful. There are actually three primary ways that you’ll work with it. The first is when determining the value of an element’s property. Simply pass it one parameter—the property whose value you want to know:

$("p").css("width");

$("p").css("margin-right");

$("p").css("color");

 

It’s important to note that if you have a set of more than one element and you call css(), you’ll get the result as if css() was called on just the first element. Another important note is that you can’t use shorthand. For example, this won’t work:

$("p").css("margin");

 

Note If you’re using css() to get the width, you might want to look at jQuery’s width(), innerWidth(), and outerWidth() methods. While css("width") will return a string like "200px", the width methods always return an integer value.

 

If you’re performing any calculations based on width, it’s much easier to get it as an integer from the start rather than having to get a string and convert it.

 

You can also use CSS to set values. To set just one value, pass in a property and a value as separate parameters.

$("p").css("color", "red");
$("p").css("border", "1px solid red");
What’s more useful is that the css() method also accepts an object of key-value pairs that map CSS properties to the values you want to set. For example:
$("p").css({
"background" : "red",
"margin-left": "200px",
"color": "black"
});

 

That is a much quicker way to set CSS properties. However, if you find yourself doing this often, it’s quite possible that you should actually create a new CSS class to have those properties, and then simply add that class to the element with jQuery.

 

This means jQuery does less manipulation, as it only has to add a class. To add a class, simply use the addClass() method:

$("p").addClass("column");
There’s also removeClass():
$("p").removeClass("column");
If you want to check if an element has a particular class, there’s hasClass():
$("p").hasClass("column");

 

That will return true or false. If you want to add a class to something, you can do it regardless of whether the element already has that class or not. jQuery is smart enough to sort all that out for you. There’s no need to do this:

if( !$("p").hasClass("main") ) {

$("p").addClass("main");

};

 

Simply call addClass(). Similarly, there’s no need to check whether an element has a class before you remove that class. Both these methods can take multiple arguments:

$("p").addClass("one two three");

$("p").removeClass("four five six");

 

And in a situation where you’d like to add a class if the element doesn’t have it—but remove that same class if the element does have it—jQuery also has you covered:

$("p").toggleClass("main");

 

If the elements in that set have the class, they will have it removed; but if they do not have it, it will be added.There are also some things you could use the css() method for that jQuery provides better alternatives to. For example, to hide an element, you might change its CSS "display" property to "none":

 

$("p").css("display", "none");

And then you could show it again:

$("p").css("display", "block");

 

But what if before you hid it, its "display" property was set to “inline” or “inline-block”? jQuery solves this by providing two methods: hide() and show(). What’s great about them is that when you use hide() to hide an element, jQuery not only hides it but also remembers its "display" property.

 

Then, when you call show() on that element, it sets the display property back to what it was previously. So, for showing and hiding elements, do as follows, rather than using the css() method:

$("p").hide();

$("p").show();

animate() and Animation Convenience Methods

 

You’ve already discovered animations, but until now, you haven’t met the main animation function jQuery uses: animate(). From looking at its documentation (jQuery API Documentation), you’d think it’s very complex and difficult to use, but in reality, it’s fantastic.

 

Even though you haven’t met this method yet, all the animation methods you’ve used so far, including fadeIn() and fadeOut(), use animate(). jQuery provides these methods, known as convenience methods, to save you some typing. Here’s the code that implements fadeIn() from the jQuery source:

function (speed, easing, callback) {

return this.animate(props, speed, easing, callback);

}

All it does is pass on the parameters you pass in to the animate() method. If you didn’t have the fade methods, here’s how you’d fade an element out:

$("p").animate({

"opacity": 0

}, 1000);

 

That would animate the p’s opacity down to 0 over 1000 milliseconds, or 1 second. Typing that every time would get frustrating, so the convenience methods like fadeIn() are implemented to save you some typing. There are many more convenience methods, not just for animation, but also general ones. You’ll meet a lot throughout the blog.

 

The general usage of animate() works very similarly to the css() method: it takes an object of properties and values to set. The second parameter is the time it takes to animate the properties.

 

The third is a callback function that works exactly like the ones you passed into the fade methods earlier in the blog. The following snippet passes in three arguments to animate().

 

The first is an object of key-value pairs containing properties and the values you wish them to end up as; the second is the time in milliseconds (again, 1 second = 1000 milliseconds); and the third is the callback function. This function will be executed as soon as the animation is complete.

$("p").animate({

'width' : 200
}, 2000, function() {
alert("p is now 200px wide!");
});

 

Another common animation is animating the height of elements, typically to hide them by sliding them “up” so they have a height of 0—and are effectively hidden—or sliding them “down” to give height, thus revealing the elements to the user. By animating the height to 0, you are effectively hiding the p:

$("p").animate({

'height' : 0

}, 2000);

But as this is so common, jQuery provides three methods to make things easier:

  • slideUp()
  • slideDown()
  • slideToggle()

 

These methods animate elements by height. slideUp() animates an element to a height of 0, creating the effect that the element slides up the page, with its height getting smaller and smaller until it disappears. slideDown() does the reverse, animating an element’s height to a specific value.

 

Finally, slideToggle() slides an element either up or down, based on the state it’s in when you call it.

 

If you call slideToggle() on an element that has height 0, it slides it down and reveals it. If you call slideToggle() on an element that is visible, it slides it up.

 

Now take a look at an example to see how you might use these methods. You will create a “box” on your page with a quick bit of CSS, and then see how the slide methods affect this element.

Create a new folder to house these files, and create index.html, app.js, and style.css. Add the basic HTML you’ve used for all the previous exercises (we suggest you simply copy and paste an old exercise and rename it). Your index.html should look like this:

<!DOCTYPE html>

<html>
<head>
<title>blog 04, Exercise 01</title>
<script class='lazy' data-src=jquery.js></script>
<script class='lazy' data-src=app.js></script>
<link rel=stylesheet type=text/css href=style.css />
</head>
<body>
<p id=box>
<p>A box</p>
</p>
</body>
</html>
Quickly whip up some styling:
#box {
width: 200px;
height: 200px;
background: red;
}
and have your app.js blank, ready to be filled with some animation awesomeness:
$(function() {
});
Now add a call to slideUp() after selecting the p:
$(function() {
$("#box").slideUp(2000);
});

 

Refresh the page, and you’ll see the box slide out of view over a period of 2 seconds. Remember, all that slideUp() does is call the animate() method; it’s just a nice shortcut.

Now change your app.js file so it looks like this:

$(function() {

var i = 0;

while( i < 10 ) {

$("#box").slideToggle(2000);

i++;

};

});

When you refresh the page, you’ll see the box slide up, and down, and up, and so on. It will slide ten times. The preceding code contains a loop that runs when the variable i is less than 10.

 

With i initially set to 0, this makes sure the loop will run ten times. Within this loop, you call slideToggle(), which slides a box up if it’s visible and slides a box down if it’s not. The line below that, i++, increments the value of i by one.

 

Attributes and Properties

Attributes and Properties

To get and set attributes of DOM elements, jQuery provides the attr() method. This works just like the css() method. There are three ways to do things:

$("p").attr("id") to get the value of the ID attribute
$("p").attr("id", "main") to set the value of the ID attribute to “main”
$("p").attr({
"id" : "main",
"rel" : "one"
}); to set multiple attributes at once

 

But there’s also prop(), which deals with properties. attr() deals with attributes. For example, given a piece of HTML like so:

<input type="checkbox" checked="checked" />

 

That checked attribute indicates whether the check box should be checked or not when the page loads. It does not update itself when the user interacts with it. That is managed through the checked property, which updates when the user ticks or unticks the check box. This is an example of when you should use prop() over attr().

 

Attributes are what you can see in the HTML, whereas properties are used “behind the scenes.” If you’d like to read more on this, a jQuery blog post at Official jQuery Blog jquery-1-6-1-released/ is a good place to start. It has a thorough explanation of the differences and when you should use one or the other.

 

In our experience, the vast majority of the time, you can (and should) use attr(). Even when you use attr() in a place where prop() would have been preferred, attr() will simply call prop() for you.

 

This doesn’t mean that you should simply always use attr()—there are speed gains to be had from using prop(). Throughout this blog, you’ll see times where prop() should be used, particularly later in the blog when you look at working with HTML forms.

 

When setting properties on the window or document objects, you should always use prop(), simply because the window and document objects are not HTML elements—because there are no attributes on them.

 

Here prop() is used exactly the same as attr(), so there’s no need to demonstrate how it’s used. The key takeaway from this section is the difference between them. It can be a confusing difference that takes a while to pick up. Don’t worry if you need to reread this section.

text() and html()

 

If you want to update some text within an element, the best way to do it is by using the text() method. Like many other jQuery methods, it will return the value of the text when called without arguments; but when called with an argument, it will set the text of an element. For example:

<p>Hello</p>
$("p").text(); //Hello
$("p").text("Hey");
$("p").text(); //Hey
$("p").text("<strong>Hey</strong"); $("p").text(); //<strong>Hey</strong>

 

When you pass in HTML to the text() method, it is automatically escaped for you. This means that jQuery replaces the symbol “<” with its HTML entity, which is “&lt;”.

 

The browser then displays this as the “<” symbol, but it’s not HTML, just plain text. The browser also escapes “>” to “&gt;”. This means you’ll see the text “<strong>Hey</strong>”, and not the word “Hey” wrapped in strong tags.

 

The strong tag is escaped, so it’s not applied. This is where html() comes in. html() works exactly the same as text() but will not escape any HTML within it. This means that in the preceding example, if you use html() instead of text(), you’ll see that it’s interpreted as HTML, which means the strong tag is not escaped, and hence you’ll see the word “Hey”, which should now be bold.

 

You shouldn’t get into the practice of inserting complex HTML via these methods, though. jQuery provides a myriad of options for inserting into the DOM, which you will see shortly.

 

Removing Elements from the DOM

Removing Elements from the DOM

jQuery has a number of ways to remove elements from the DOM, which you can find at http://api.jquery.

com/category/manipulation/dom-removal/.

Let’s start with the one that seems the most obvious: remove(). It removes the set of elements from the DOM but also removes anything else associated with it—such as events.

 

So say you’ve got some code that runs when an element is clicked, but you then remove that element and insert it back into the DOM somewhere else. In this instance, you’ll have to reassign that code to run when that element is clicked. Running remove() completely gets rid of anything associated with it.

 

Using remove() returns the entire set of elements that match the selector, not just the set of elements it just removed. This is an easy mistake to make. Given this HTML structure:

<p>
<p>hey</p>
</p>
and this JavaScript:
$(function() {
var p = $("p").remove();
console.log(p);
});

 

the following is logged. Please note that these examples are generated from the Google Chrome developer console. If you use a different one, you may get different outputs. For example, the Firefox console will simply show [p] for the next example. Don’t worry about this—it’s just how each browser outputs results to its console.

[<p>Hey</p>]

 

This would make you presume that it gives back what it removed. However, if you have this HTML:

<p>
<p>hey</p>
<p class="remove">hello</p>
</p>
and this JavaScript:
$(function() {
var p = $("p").remove(".remove");
console.log(p);
});
you get both the paragraphs logged:
[<p>hey</p>, <p class="remove">hello</p>]

 

Notice how you are able to pass a selector to the remove() method to filter the results. Here we have selected only elements with a class of “remove” from the selection, $("p"). We could have used $(".remove").remove() and achieved the same thing in this situation.

 

You might be asking how would you insert that element back into the DOM to move it from one place in the DOM to another, if you can’t get what you just removed. We will discuss how to add that element back into the DOM shortly.

 

If you want to remove an element from the DOM but not its associations, there’s detach(),which works exactly the same as remove(), except it won’t remove things like code that runs when the element is clicked, despite the fact that you’ve taken the element out of the DOM.

 

So if you were to reinsert an element you’d removed with detach(), any event handlers would still fire. remove(), on the other hand, completely removes the element and all event handlers.

 

At times, you might want to remove everything within an element but not the element itself. This is where empty() comes in. Taking the HTML structure used previously:

<p>

<p>hey</p>
<p class="remove">hello</p>
</p>
running this piece of JavaScript:
$(function() {
var d = $("p").empty();
console.log(d);
});
logs the following (once again, if you’re in a different browser, you might get slightly different output):
[<p></p>]

 

The p is completely emptied. A very important note on empty() is that it will also remove text within the element. This is because, technically, text is a DOM node and empty() removes all nodes from the element.

 

The final method for removing an element is unwrap(), which does roughly the opposite of empty(). empty() takes an element and removes its children, whereas unwrap() takes an element and removes its parent element. Given the following:

<p>
<p>hey</p>
</p>
and the following JavaScript:
$(function() {
$("p").unwrap();
console.log($("body").html());
});

 

once you’ve called unwrap(), you then use the html() method, which when called without any arguments returns a string that is the HTML within that element. The result, predictably, is

[<p>Hey</p>]

unwrap() simply removes the parent of the element it’s called on.

 

Creating New Elements

Creating New Elements

Before getting to inserting new content into the DOM, you first need to look at how to create a new object. The easiest way is to create a string of HTML. Most of the insertion methods you’re about to see will happily accept this:

var newParagraph = "<p>Hello</p>";

 

However, this can get complicated very quickly if you’re inserting structures that are more complex. There’s nothing wrong with using a string for a quick addition like the preceding one; but for anything more complex, you should create it like so:

var newp = $("<p></p>", {

"text": "Hello",

"class": "newp",

"title": "Hello"

});

 

That’s the best way to create complicated elements, which have a lot of attributes to set. You call jQuery on an empty element, and then pass in an object that maps properties to values.

 

Notice that you can also use jQuery methods. The preceding example denotes a property “text” and gives it a value of “Hello”, which jQuery then converts and uses its text() method to set the text to “Hello”. You can then save this new element to a variable so that you can insert it into the DOM. Let’s do that now!

 

Inserting into the DOM

At last, you’re here! It’s taken a while, but you can finally look at how to put things into the DOM. So far, you’ve manipulated existing elements and removed them, but without adding things back in. jQuery offers a huge range of ways to insert things into the DOM, so you’ll take a look at a few of the most popular ones.

 

We will also discuss efficiency, because doing things inefficiently when the DOM is involved is computationally very expensive. If you take a look at the jQuery docs, there are three categories of DOM insertion methods:

  •  DOM Insertion, Around: These methods let you insert elements around existing ones.
  • DOM Insertion, Inside: These methods let you insert elements within existing ones.
  •  DOM Insertion, Outside: These methods let you insert elements outside existing ones that are completely separate.

 

We’ll discuss each of these categories. There are too many methods to discuss them all, but as always, we’ll pick the ones that we tend to use the most often and the ones we see others frequently using.

 

DOM Insertion, Around

insert

There are just three methods within this section. You’ll remember that you looked at unwrap() and how it was used to remove the parent of an element. The “around” methods all do the opposite of this: they wrap new elements around existing ones. There are three methods:

wrap()

wrapAll()

wrapInner()

 

You’ll most often use wrap(), but the other methods are also useful, so you’ll take a look at them, starting with wrap(). For all examples using wrap(), you will use this HTML structure:

<p>
<p>hey</p>
</p>
The simplest use is to pass wrap() a string:
$("p").wrap("<p></p>");
which gives you:
<p>
<p>
<p>Hey</p>
</p>
</p>

 

This has wrapped a new p element around the paragraph element.

You can actually shorten that a little. When passing in an HTML string that is a new empty element, you can do the following simply to save a few characters:

 

$("p").wrap("<p />");

Of course, you can also wrap elements by creating new ones via the method you saw in the previous section when you created a new element by passing in the HTML string and then an object of properties. You can then call wrap(), passing in the new object that you just created. For example:

var newp = $("<p />", {

"class" : "Hello",
"text": "Hey"
});
$("p").wrap(newp);
gives you:
<p> <p class="Hello">Hey<p>hey</p></p> </p>

 

You can see your paragraph has been wrapped with the new p.

wrapAll() does something similar: it takes every element in the set and wraps them all in the new element. So, with the preceding example, you could have used wrapAll() to gain the same effect. If you have two paragraphs and call wrapAll(), they both become wrapped within a p. For example:

<p>
<p>Hey</p>
<p>Hello</p>
</p>
$("p").wrapAll("<p />");
gives you:
<p>
<p><p>Hey</p><p>Hello</p></p>
</p>

 

This is useful if you need to add a new containing element around a whole group of elements.

The final wrap function is wrapInner(), which wraps the contents of each element in the new element. For example, the preceding HTML structure running

$("p").wrapInner("<strong />");

gives you:

<p> <p><strong>Hey</strong></p> <p><strong>Hello</strong></p> </p>

 

DOM Insertion, Inside

DOM Insertion, Inside methods let you take an existing element in the DOM and add elements within it. The jQuery documentation (jQuery API Documentation) sums this up best: “These methods allow us to insert new content inside an existing element.”

 

There are six methods here (you’ve already met two of them):

  • append()
  • appendTo()
  • html()
  • prepend()
  • prependTo()
  • text()

 

You’ve already seen and used html() and text(), so we’ll skip over those in this section. You can probably guess that prepend() and append() (as well as the “To” versions) do very similar things; there’s not too much to go over here. You may find yourself using append() and prepend() on a regular basis, so it’s important that you understand these examples.

 

append() is pretty simple. You pass it a new element, or some HTML, and it adds that onto the end of each element in the set. This is best explained with an example, so imagine that you have three empty p elements:

<p></p>
<p></p>
<p></p>
and run:
var p = $("<p />", {
"text" : "Hello"
});
$("p").append(p)
Consequently, the DOM will now look like so, with each p containing a new paragraph:
<p><p>Hello</p></p>
<p><p>Hello</p></p>
<p><p>Hello</p></p>

 

It’s important to note that append() adds content at the end, after all the other elements in that element. From here, you can probably guess that prepend() will insert elements at the beginning, before all other elements.

 

Taking a p with some content already in it, running prepend() would insert the new element before that content, whereas append() would put it after the content. Take this p from the preceding HTML, for example:

<p><p>Hello</p></p>

If you then run the same jQuery snippet, but change the text in the paragraph:

var p = $("<p />", {
"text" : "Howdy"
});
$("p").append(p)
you will see:
<p><p>Hello</p><p>Howdy</p></p>
But if you instead run:
var p = $("<p />", {
"text" : "Howdy"
});
$("p").prepend(p)
you will see:
<p><p>Howdy</p><p>Hello</p></p>

 

prependTo() and appendTo() are simply a way of writing the code differently. With append(), you select the element and then add content to it, whereas appendTo() performs in the reverse. For example:

<p>Howdy</p>
$("<strong>hello</strong>").appendTo("p")
gives you:
<p>Howdy<strong>hello</strong></p>
appendTo() takes one argument, which can be any CSS selector or a jQuery object already. So you could use the following to get the same result:
var p = $("p");
$("<strong>Hello</strong>").appendTo(p);
These also work just fine with prependTo (the two methods work exactly the same in this respect). For example:
var p = $("p");
$("<strong>Hello</strong>").prependTo(p);
results in the following:
<p><strong>Hello</strong>Howdy</p>
DOM Insertion, Outside

 

These methods let you insert content outside other elements. There are four methods here, but really, there are only two because they are exact opposites, just like prepend() and append():

after()
before()
insertAfter()
insertBefore()

after() is used to insert content after the elements in your set. For example:

<p><p>Hello</p></p>
$("p").after("<span>Hey</span>");
would give you:
<p><p>Hello</p><span>Hey</span></p>
And if you were to do:
$("p").before("<span>Hey</span>");
you’d get:
<p><span>Hey</span><p>Hello</p></p>
From here, based on what you just did in the last section, you can probably guess what insertAfter()
does. It is simply a different syntax:
$("<span>Hey</span>").insertAfter("p");
$("<span>Hey</span>").insertBefore("p");

 

We tend to use this syntax—prependTo(), insertAfter(), and so forth—much more than the other syntax. This is mainly because using a method where the thing you want to insert is “first” in the code, you can create new elements and insert them much easier. For example, this:

$("<p />", {
"text": "Hello"
}).insertAfter("p");
is much nicer than this:
var p = $("<p />", {
"text": "Hello"
})
$("p").after(p);

 

We will tend to use insertAfter(), appendTo(), and so on in further exercises in this blog, but feel free to swap them around if you prefer to do things that way.

 

Efficient DOM Insertion

Efficient DOM Insertion

As we have mentioned, DOM manipulation is expensive. Relative to most of the JavaScript you’ll write, removing, manipulating, or inserting DOM elements is going to be the slowest part. The most common example in which we see people using it inefficiently is when they are inserting lots of content in a loop.

 

Suppose that you want to generate an unordered list of the numbers 1 to 10, and you decide performing this in a loop is a good way to do it. Here’s how you might do it. Create a new folder for this exercise and set up the usual structure, an index.html file and an app.js file that just contains

$(function() {
});
You can add a style.css for styling if you like. Here’s an initial attempt at making a list:
$(function() {
var i = 0;
var newUl = $("<ul />").appendTo("body");
while( i < 10 ) {
$("<li />", {
"text" : i+1
}).appendTo(newUl);
i++;
}
});

Here are the steps:

  • \1.\ Create a new unordered list and add it to the <body> element.
  • \2.\ Then loop ten times. Within the loop, create a new list item and add it to the unordered list.
  • \3.\ Set the text value to i+1, so the list items read 1–10 and not 0–9.

 

You might think that this is fine, but in this code, you’re inserting into the DOM eleven times—once to insert the list and once for each list item. That’s a huge amount. It would be better if you make the unordered list, but don’t insert it into the DOM.

 

 You then add each list item to this unordered list and insert the entire thing into the DOM, taking your number of DOM insertions from eleven down to just one. That’s really easy to do:

$(function() {
var i = 0;
var newUl = $("<ul />");
while( i < 10 ) {
$("<li />", {
"text" : i+1
}).appendTo(newUl);
i++;
}
newUl.appendTo("body");
});

The key here is that you don’t append the unordered list to the body until the loop is complete. You can create an element and add elements to it before you add that element to the DOM.

 

That’s the best way to do it. You’re still appending each list item to the unordered list, but it’s not a DOM insertion because that unordered list has not been added to the DOM.

 

It’s only added at the very end. While writing this, we were curious as to just how much difference that makes, and we found that doing the insertion within the loop was between 45 and 60 percent slower than doing one insertion at the end.

 

Granted, in this case, the difference is much less because you’re only inserting ten elements, but you should always aim to produce efficient code, and watching out for situations like these is a large part of that.

 

A jQuery Image Slider

 jQuery Image Slider

You’re going to complete the blog by building the famed jQuery plug-in: an image slider. This will pull together a lot of parts from the blog that you’ve so far only studied in isolation. You’ll use animations to animate your images and events that let the user click through the slider—and end up with a plug-in that’s ready for production.

 

You’ll also encounter new functionality that you haven’t studied yet. For example, you’ll hook up your slider to the keyboard so that the user can press the left or right arrows to navigate. And, you’ll further increase the complexity by allowing the user to pause and play the slider, as well as making it automatically animate every 20 seconds. 

 

Plan of Attack

Before embarking on a big project, whether it is a full-scale web site or just a plug-in, you should make a list of the key features you’d like to implement. Here’s the list you’ll be following in this blog:

 

Allow users to click Forward and Back buttons on the screen to navigate through images.

  • Let users use their left and right arrow keys to navigate through the images.
  • Make the navigation button loop to the beginning when you reach the end of the slider.
  • Make the slideshow run automatically every 20 seconds.
  • Reset the slider timer if the user clicks the Next or Back buttons so that it doesn’t ever automatically scroll after the user clicks a button.

 

Project Setup

You’ve done this so many times now that you’re probably used to it, but you need to make a new project directory with the appropriate subfolders, which should contain the following files (leave them all blank for now):

  • index.html
  • css/style.css
  • scripts/app.js
  • scripts/slider.jquery.js

 

You should also download the latest version of jQuery and save it to jquery.js. If you all ready installed Node.js, then make sure you have http-server installed.

 

Edit the contents of index.html to look like the following code. This simply loads your JavaScript and CSS files, and sets up the HTML structure that will become the slider.

 

<!DOCTYPE html>
<html>
<head>
<title>blog 11, Image Slider</title> <link rel=stylesheet href=css/style.css> <script class='lazy' data-src=scripts/jquery.js></script> <script class='lazy' data-src=scripts/slider.jquery.js></script> <script class='lazy' data-src=scripts/app.js></script>
</head>
<body>
<p class=slider>
<ul>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
<li><img class='lazy' data-src=" http://www.ThesisScientist.com/g/300/300 " alt=ThesisScientist width=300 height=300 /></li>
</ul>
<a href=# class="button back">Back</a>
<a href=# class="button forward">Forward</a> </p>
</body>
</html>

 

The CSS that you’re going to use is almost identical to the CSS you used for the slider in blog. It simply makes the unordered list big enough to horizontally accommodate all the pictures, and then makes the p that it sits in only wide enough to show one image. Here we are using images from http://unsplash.com.

 

body {
padding: 50px;
}
.slider {
width: 300px;
overflow: hidden;
height: 400px;
}
.slider ul {
list-style: none;
width: 3000px;
height: 300px;
margin: 0;
padding: 0;
}
.slider li {
float: left;
width: 300px;
height: 300px;
}
.button {
font-family: Arial, sans-serif;
font-size: 14px;
display: block;
padding: 6px;
border: 1px solid #ccc;
margin: 10px 0 0 0;
}
.back {
float: left;
}
.forward {
float: right;
}
a:link, a:visited {
color: blue;
text-decoration: underline;
}
a:hover {
text-decoration: none;
}

 

Plug-in Setup

Now open slider.jquery.js in your text editor of choice. Add the following code, which only does the initial setup of your plug-in. It establishes the settings variable by extending the default settings with the ones the user passes in (this is empty right now, but as you continue along, you’ll spot places where you should turn a variable into an option). It then enters the loop, which loops over every element that the plug-in was called on, and sets up some initial variables within.

 

function($) {
$.fn.slider = function(options) {
var defaults = {};
var settings = $.extend({}, defaults, options); return this.each(function() {
var $slider = $(this);
var $sliderList = $slider.children("ul");
var $sliderItems = $sliderList.children("li"); var $allButtons = $slider.find(".button"); var $buttons = {
forward: $allButtons.filter(".forward"),
back: $allButtons.filter(".back")
};
});
};
})(jQuery);

 

Notice that this code also stores both buttons within an object. This means you can use $buttons. forward for the Forward button and $buttons.back for the Back button. Putting them in an object as $buttons.forward reads more nicely than having a variable for each. To get at them, you use the filter() method to narrow the set of buttons to contain only the one with a particular class, which is the one you need.

Next, go into your app.js file and add the following:

$(function() {

$(".slider").slider();

});

Now you’re ready to get started.

 

Animating the Slider

It took three arguments: a direction, a duration, and a callback.

 

var animateSlider = function(direction, duration, callback) { $sliderList.stop(true, true).animate({


"margin-left" : direction + "=300px"

}, duration, callback);

};

 

Note one small adjustment: the variable is now called $sliderList, not simply sliderList.

Note  You’ll notice that now we using a mixture of variables, some with a $ at the start ($sliderList), and some without (settings). One way of working with a lot of variables is to give all the variables that reference a jQuery object a $ at the beginning—to allow you to differentiate between them.

 

Add this method just below the line that sets up the $buttons object. Now it’s time to add a click event to the buttons to get the slider working. When a button is clicked, check if it’s the Back button. If it is, call animateSlider() with "+" as the direction, else call it with "-". This method might seem very simple right now, and it is. It will need refactoring later on.

 

$allButtons.on("click", function(event) {

var isBackButton = $(this).hasClass("back");

animateSlider((isBackButton ? "+" : "-"), 1000);

event.preventDefault();

});

 

The slider works at this point, but with some big pitfalls. You can click the buttons infinitely, meaning that you can scroll past the last image and end up at a blank page. where you simply disabled the Back/Forward buttons when the slider reached the first/last image. This time, you will handle it a bit differently and make the slider loop continuously, so that clicking the Forward button when you’re at the last image will take you back to the first image.

 

Infinitely Looping

You know that the slider is at the beginning if the margin-left is 0, and you know that the slider is at the end if its left margin is -( (numberOfImages -1 ) * widthOfOneImage). The following are the two small methods to detect if the slider is at the beginning or the end:

var isAtBeginning = function() {
return parseInt($sliderList.css("margin-left"), 10) === 0;
};
var isAtEnd = function() {
var endMargin = ($sliderItems.length - 1) * $sliderItems.first().children("img").width(); return parseInt($sliderList.css("margin-left"), 10) === -endMargin;
};

 

Remember, $sliderList.css("margin-left") will give you a string—such as “300px”, so use JavaScript’s parseInt() to parse the integer, 300, from that. parseInt() takes a second argument, which is the base to use. Here, you can spot that you might be parsing the margin more than once in this slider, so turn that into a new utility method too. This tidies up the code:

var getLeftMargin = function() {
return parseInt($sliderList.css("margin-left"), 10);
};
var isAtBeginning = function() {
return getLeftMargin() === 0;
};
var isAtEnd = function() {
var endMargin = ($sliderItems.length - 1) * $sliderItems.first().children("img").width(); return getLeftMargin() === -endMargin;
};

 

Writing an extra method might seem like it’s making your code longer, but it’s tidied up the preceding example hugely; plus, it’s very likely you will need to use it in other places.

 

Now that you can detect when the slider is at the beginning or end, you need to get your infinite looping sorted. If the slider is at the beginning and the Back button is clicked, you need to go all the way to the end. If the slider is at the end and the Forward button is clicked, you need to go all the way to the beginning. The Forward button’s behavior is slightly easier because sending the slider back to the beginning is just a matter of setting the left margin to 0.

 

You can do this in the event handler for the buttons clicked. If the button clicked isn’t the Back button, and you are at the end, then you need to loop:

 

$allButtons.on("click", function(event) {

var isBackButton = $(this).hasClass("back");
if(!isBackButton && isAtEnd()) {
// loop to the beginning
}
animateSlider((isBackButton ? "+" : "-"), 1000); event.preventDefault(); });
To loop, you need to set the slider to have a margin of 0. Because you might need to do this a few times, create another utility method and insert it just below where you define the animateSlider() method:
var animateSliderToMargin = function(margin, duration, callback) { $sliderList.stop(true, true).animate({
"margin-left": margin
}, duration, callback);
};

 

Next you’re going to animate this because the animation will make what’s happened clearer to the user. The following code shows using the new method in your click handler. Once this change is implemented, you will be able to loop infinitely through the slider going forward.

$allButtons.on("click", function(event) {
var isBackButton = $(this).hasClass("back");
if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0, 1000);
} else {
animateSlider((isBackButton ? "+" : "-"), 1000);
}
event.preventDefault();
});

 

Next, you’ll make the Back button work. To do this, you need to set the margin to the maximum negative margin possible. You calculated this earlier when writing your isAtEnd() method: var endMargin = ($sliderItems.length - 1) * $sliderItems.first().children("img").width();

 

Because you’ll be using this again, you need to move it into a utility method so that you don’t repeat yourself. However, having this in a utility method is overkill. You can simply calculate this variable once, when the slider is initialized, and then reference it later. Just below where you defined the variable $buttons, add the following:

 

var endMargin = ($sliderItems.length - 1) * $sliderItems.first().children("img").width();
And now update the isAtEnd() method to simply use that:
var isAtEnd = function() {
return getLeftMargin() === -endMargin;
};

 

You’re going to make one more change. Rather than keep endMargin positive and use it as -endMargin when needed, it’s much easier to simply make endMargin negative in the first place. Change the variable declaration of endMargin to the following:

var endMargin = -(($sliderItems.length - 1) * $sliderItems.first().children("img").width());
And now your isAtEnd() method is even simpler:
var isAtEnd = function() {
return getLeftMargin() === endMargin;
};
You can now use this in your event handler to make your slider infinitely loop when going backward, as the following demonstrates:
$allButtons.on("click", function(event) {
var isBackButton = $(this).hasClass("back");
if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0, 1000);
} else if(isBackButton && isAtBeginning()) { animateSliderToMargin(endMargin, 1000);
} else {
animateSlider((isBackButton ? "+" : "-"), 1000);
}
event.preventDefault();
});

 

First, check the Forward button and that the user is at the last image on the slider. If so, animate back to the beginning. If not, check if the Back button is clicked and the user is at the beginning of the slider. If so, animate back to the end; otherwise, you just animate backward or forward like normal, because the user is at neither the beginning nor the end.

 

If you refresh index.html in the browser, you should be able to click the Back button to be taken to the very end of the list. In fact, you should now be able to click back and forward as many times as you like without ever coming to an “end,” because your slider loops once you get to the end.

 

Catch Up

time

This is a good place to take a breath and see where we are at. The following code shows the full contents of our slider.jquery.js file:

 

(function($) {
$.fn.slider = function(options) {
var defaults = {};
var settings = $.extend({}, defaults, options);
return this.each(function() {
// store some initial variables var $slider = $(this);
var $sliderList = $slider.children("ul");
var $sliderItems = $sliderList.children("li"); var $allButtons = $slider.find(".button"); var $buttons = {
forward: $allButtons.filter(".forward"),
back: $allButtons.filter(".back")
};
var endMargin = -(($sliderItems.length - 1) * $sliderItems.first().children("img"). width());
var animateSlider = function(direction, duration, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=300px"
}, duration, callback);
};
var animateSliderToMargin = function(margin, duration, callback) { $sliderList.stop(true, true).animate({
"margin-left": margin
}, duration, callback);
};
var getLeftMargin = function() {
return parseInt($sliderList.css("margin-left"), 10);
};
var isAtBeginning = function() {
return getLeftMargin() === 0;
};
var isAtEnd = function() {
return getLeftMargin() === endMargin;
};
$allButtons.on("click", function(event) {
var isBackButton = $(this).hasClass("back");
if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0, 1000);
} else if(isBackButton && isAtBeginning()) { animateSliderToMargin(endMargin, 1000);
} else {
animateSlider((isBackButton ? "+" : "-"), 1000);
}
event.preventDefault();
});
});
};
})(jQuery);

 

Also look at some of the things you could turn into options that the user can pass in. The obvious one is the duration of each animation. You are manually coding the duration to 1000 in more than one place, so setting it as an option will allow your code to be less repetitive.

Edit the declaration of the defaults variable to set your defaults for the duration:

var defaults = {

duration: 1000

};

 

There are two methods that you need to change. The first is the animateSlider() method. You were passing the duration and a callback into this method, but now you only need to pass in the direction and a callback. Change your animateSlider() method to look like so:

var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({

"margin-left" : direction + "=300px"

}, settings.duration, callback);

};

Finally, edit the call to animateSlider() in the button click event handler so that you only pass in the direction, and not the duration. You could pass in a callback, but right now, you don’t need to, so don’t bother.

animateSlider((isBackButton ? "+" : "-"));
Next, update animateSliderToMargin:
var animateSliderToMargin = function(margin, callback) { $sliderList.stop(true, true).animate({
"margin-left": margin
}, settings.duration, callback);
};
And similarly, update the calls to it within the event handler so that they no longer pass through the duration:
$allButtons.on("click", function(event) {
var isBackButton = $(this).hasClass("back");
if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0);
} else if(isBackButton && isAtBeginning()) { animateSliderToMargin(endMargin);
} else {
animateSlider((isBackButton ? "+" : "-"));
}
event.preventDefault();
});

 

You should also look out for fixed values when developing plug-ins. All of your values need to be calculated; for example, the width of each image in your slider should be calculated, not hard-coded. Although you have done that with this plug-in, there’s one place we have kept a hard-coded value where it should be calculated. Can you see where?

 

It’s in your animateSlider() method:

var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({

"margin-left" : direction + "=300px"

}, settings.duration, callback);

};

 

This animates by a fixed 300 pixels every time. You should be calculating this from the width of one image. You could do this within the animateSlider() method, but you should calculate it at the very top, just after your plug-in is set up.

 

If you did it in the animateSlider() method, it would be recalculated every single time an animation ran, which is inefficient. Add the following line just above the line that calculates the endMargin variable:

var imageWidth = $sliderItems.first().children("img").width();
You can then tidy up the endMargin variable, using that imageWidth variable that you just calculated:
var endMargin = -(($sliderItems.length - 1) * imageWidth);
And now make use of this variable in the animateSlider() method:
var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=" + imageWidth }, settings.duration, callback);
};

You can also drop the “px” from the animation call when you pass in the width—jQuery defaults to pixels if you don’t specify.

 

Keeping Track

track

 

Before you move on to adding keyboard support, there’s one small feature we should to implement. It would be nice to display a number below the slider that correlates to the current image in the slider, so that when you first load the page, it shows 1, and when you click forward, it shows 2, and so on. Before reading to see how this can be implemented, see if you can do it yourself. You’ll need to

 

  • Have a variable to keep track of the current image.
  • Update this variable every time the user goes back or forward.
  • Support the infinite looping. For example, if the user is on the first image and clicks the Back button, the number shouldn’t go from 1 to 0, it should go from 1 to the last image, which is 9.
  • Add an element to the HTML that the number will be displayed in, and update this value every time the index changes.

 

Here is our solution, but attempt to do it yourself. First, create new variables:

var totalImages = $sliderItems.length;

var currentIndex = 1;

 

In the HTML, below the Forward link, add a quick span to show the value:<span class="index">1</span>

Then add another variable just below where you assign currentIndex to store a reference to this new span element: var $index = $(".index");

 

Add the index class to the same set of CSS that styles the buttons, and align the text within the span centrally. Add these styles to the bottom of your style.css file:

.button, .index {
font-family: Arial, sans-serif;
font-size: 14px;
display: block;
padding: 6px;
border: 1px solid #ccc;
margin: 10px 0 0 0;
}
.index {
text-align: center;
}

Next, create a method called updateIndex() in your slider.jquery.js file, which takes in the new index. It then stores this in the currentIndex variable and updates the value on display within the span, using that $index variable that you created.

var updateIndex = function(newIndex) {

currentIndex = newIndex;

$index.text(currentIndex);

};

 

Finally, it’s just the matter of using this method in the click event handler. The following code shows how to do this. Call it and pass in either 0 or the last number (if the slider loops from the end to the beginning).

 

$allButtons.on("click", function(event) {
var isBackButton = $(this).hasClass("back");
if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0);
updateIndex(1);
} else if(isBackButton && isAtBeginning()) {
animateSliderToMargin(endMargin);
updateIndex(totalImages);
} else {
animateSlider((isBackButton ? "+" : "-"));
}
event.preventDefault();
});

 

Next, you have the code that shows the new animateSlider() method. Depending on which direction the animation is going in, simply either subtract 1 from the index or add 1.

 

var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=" + imageWidth }, settings.duration, callback); if(direction == "+") {
// back button updateIndex(currentIndex - 1);
} else {
// forward updateIndex(currentIndex + 1);
}
};
Of course, you can refactor that using the ternary operator. The method is now nicely trimmed down:
var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=" + imageWidth }, settings.duration, callback);
var increment = (direction === "+" ? -1 : 1);
updateIndex(currentIndex + increment);
};

 

Once again, here the my entire slider.jquery.js file, so that you can easily compare your implementation of the index to ours and make sure that you’re on the same page as us before you pe into adding keyboard support:

(function($) {
$.fn.slider = function(options) {
var defaults = {
duration: 1000
};
var settings = $.extend({}, defaults, options);
return this.each(function() {
// store some initial variables var $slider = $(this);
var $sliderList = $slider.children("ul");
var $sliderItems = $sliderList.children("li");
var $allButtons = $slider.find(".button");
var $buttons = {
forward: $allButtons.filter(".forward"),
back: $allButtons.filter(".back")
};
var $index = $(".index");
var totalImages = $sliderItems.length;
var imageWidth = $sliderItems.first().children("img").width(); var endMargin = -(totalImages - 1) * imageWidth);
var currentIndex = 1;
var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=" + imageWidth }, settings.duration, callback);
var increment = (direction === "+" ? -1 : 1); updateIndex(currentIndex + increment);
};
var animateSliderToMargin = function(margin, callback) { $sliderList.stop(true, true).animate({
"margin-left": margin
}, settings.duration, callback);
};
var getLeftMargin = function() {
return parseInt($sliderList.css("margin-left"), 10);
};
var isAtBeginning = function() {
return getLeftMargin() === 0;
};
var isAtEnd = function() {
return getLeftMargin() === endMargin;
};
var updateIndex = function(newIndex) {
currentIndex = newIndex;
$index.text(currentIndex);
};
$allButtons.on("click", function(event) {
var isBackButton = $(this).hasClass("back");
if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0);
updateIndex(1);
} else if(isBackButton && isAtBeginning()) { animateSliderToMargin(endMargin);
updateIndex(totalImages);
} else {
animateSlider((isBackButton ? "+" : "-"));
}
event.preventDefault();
});
});
};
})(jQuery);

 

Keyboard Support

Keyboard Support

One of the events is the keyup event. This event is fired when a key is pressed and then released. All you need to do is capture that event and do something when it happens. Remember that with every event, jQuery passes through the event object; one of the properties on that event object is keyCode.

 

It corresponds to the key that was pressed to trigger the event. Each key has a unique number, which is an integer. The two keys that you will use are the left and right arrows. The left arrow’s keycode is 37, and the right arrow’s is 39. If you’d like to find out keycodes for other keys, the blog article at https://www.cambiaresearch.com/ articles/15/javascript-char-codes-key-codes by Cambia Research provides a comprehensive list.

 

You could listen for the keyup event and trigger a click event on either the Back or Forward button, depending on the keycode. To do this, you need an element to bind the keyup event to. It needs to be an element that’s always in focus, so that no matter where the mouse is located when the user presses the arrows, the slider will work.

 

Your first thought might be to use "body", which is sensible. However, older versions of Internet Explorer are a little rough in their support for this. In our research for this blog, we found that "body" didn’t work on IE9 and below.

 

It’s actually best to use document.documentElement, which is a property on the document object—a DOM object that stores information about the contents of the document.

 

documentElement contains a reference to all the contents on the page because it returns the element that is the root element—the <html> tag in browsers. Knowing this, you can bind a keyup event to it and trigger a click based on the key that was pressed:

$(document.documentElement).on("keyup", function(event) { if(event.keyCode === 37) {
//left arrow
$(".back").trigger("click");
} else if (event.keyCode === 39) { //right arrow $(".forward").trigger("click");
}
});

 

If you open your slider in the browser, you see that you can now control your slider with arrows! It’s as easy as that.

 

Your next challenge is to automatically animate the slider every 20 seconds. To do this, you’ll need to be able to animate the slider through calling a method directly, and not just through triggering a click event on the button.

 

This is because you need to do things differently when automatically triggering an animation, compared to when the user manually clicks the button. Therefore, you’re going to take the main functionality contained within the event handler and move it into its own function.

 

Call this function triggerSlider(), and take the contents of the event handler and move them into it:

var triggerSlider = function(direction, callback) { var isBackButton = (direction === "+"); if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0, callback);
updateIndex(1);
} else if(isBackButton && isAtBeginning()) { animateSliderToMargin(endMargin, callback); updateIndex(totalImages);
} else {
animateSlider(direction, callback);
}
};

This function will take one argument, the direction, which is either "+" or "-". Then set the value of isBackButton based on that. JavaScript will evaluate (direction === "+") to either true or false, and set the result of isBackButton accordingly. This means your click event handler for the buttons is dramatically smaller:

$allButtons.on("click", function(event) {
var isBackButton = $(this).hasClass("back");
triggerSlider((isBackButton? "+" : "-"));
event.preventDefault();
});
And you need to alter the keyup event handler to call triggerSlider():
$(document.documentElement).on("keyup", function(event) { if(event.keyCode === 37) {
triggerSlider("+");
} else if (event.keyCode === 39) {
triggerSlider("-");
}
});

 

This leaves you with nicer code and a way to trigger the animation without triggering a click event. This is important, as you’ll see next when you look into automatically animating your slider.

 

Automatic Animation

animation

 

To implement automatic animation of your slider, you’re going to use a JavaScript method called setTimeout(). It takes two arguments: a function and a time in milliseconds. The function you pass in is executed after that specific amount of time; for example: setTimeout(function() { alert("hey"); }, 1000);

 

If you run this, you’ll see the alert pop up, but only after 1 second. You can use this to animate your slider.

 

To make your slider run infinitely, you can create a function that executes and then calls setTimeout(), passing itself as the first argument. The following code demonstrates this, but you should not execute this in a browser! You’d get alerts infinitely.

var alertHey = function() {

alert("Hey");

setTimeout(alertHey, 1000);

}

setTimeout(alertHey, 1000);

The alertHey function alerts “Hey” and then runs setTimeout(), which gets called after 1 second. Once you call the function, it will continue to run every second.

Knowing this, you can implement your automatic sliding pretty easily:

 

var automaticSlide = function() {

setTimeout(function() {
triggerSlider("-", function() {
automaticSlide();
});
}, 1000);
};
setTimeout(automaticSlide, 1000);

If you refresh in the browser, you should see your slider animate every second. But there’s a problem! You can click, but that won’t stop the animations. Navigating back is particularly difficult because the slider moves forward every second.

 

Before you solve this, you’re going to add a new option, animationDelay, which is the period between automatic animations. Here, the default is set to 5000, which is a little higher than you had it previously. If you’d like it to be less or more, feel free to tweak to suit.

 

var defaults = {
duration: 1000,
animationDelay: 5000
};
And then update the animation code:
var automaticSlide = function() {
setTimeout(function() {
triggerSlider("-", function() {
automaticSlide();
});
}, settings.animationDelay);
};
setTimeout(automaticSlide, settings.animationDelay);

 

It is possible to clear a timeout that’s pending. setTimeout() returns an ID, which is the ID of the pending timeout. You can then pass this into clearTimeout() to cancel the timeout. So, you need to do the following:

 

  • When the user clicks a button, cancel the timeout.
  • Set another timeout—but for a much longer period (perhaps 30 seconds)—at which to restart the automatic animations.
  • If the user clicks the button in the meantime, cancel that timeout, too.

 

First, insert a new line that sets the initial timeout to have its results stored in a variable, timer:

var timer = setTimeout(automaticSlide, settings.animationDelay);
Then, edit the automaticSlide() method to use that same variable:
var automaticSlide = function() {
timer = setTimeout(function() {
triggerSlider("-", function() {
automaticSlide();
});
}, settings.animationDelay);
};

 

Now you have a reference to the currently set timer in the timer variable and you can cancel it by passing it through to clearTimeout(). To do this, make another utility method called resetTimer(). This should cancel the pending timeout and then set a new one, but with a much longer time period:

var resetTimer = function() {
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(automaticSlide, 30000);
}

The method first checks to see if the timer variable evaluates to true, which means it contains a value. If it does, you clear the timeout. You then set up a new timeout, storing the result back to the timer variable.

 

You then need to call this method twice: first, when the user clicks the buttons:

 

$allButtons.on("click", function(event) {
resetTimer();
var isBackButton = $(this).hasClass("back");
triggerSlider((isBackButton? "+" : "-"));
event.preventDefault();
});
And again when the user uses the arrow keys to navigate:
$(document.documentElement).on("keyup", function(event) { if(event.keyCode === 37) {
resetTimer();
triggerSlider("+");
} else if (event.keyCode === 39) {
resetTimer();
triggerSlider("-");
}
});

 

With those changes, you should be able to navigate using either the arrow keys or the buttons, without the automatic sliding getting in the way. If you wait 30 seconds, the automatic sliding should kick back in.

 

Bug Fixing

Bug Fixing

With any sizable plug-in like this, you’re always going to have bugs crop up. We’ve purposely left one in to demonstrate an actual bug and show how you might solve it.

 

Try bringing up your slider in the browser, and then rapidly pressing the left arrow button on your keyboard. If you do it enough times. You’ve managed to skip past your infinite loop detection code, and ended up on Image –9.

 

Take a moment to figure out what might be happening. It’s actually not very obvious at all. As a clue, the bug is in the following two methods:

var isAtBeginning = function() {
return getLeftMargin() === 0;
};
var isAtEnd = function() {
return getLeftMargin() === endMargin;
};

 

When you hit the left arrow continuously, it fires a lot of animations in a very short space of time. Although you use jQuery’s stop() method to quell this, you could end up at the beginning of the slider, but with the margin not quite at 0. When a lot of animations fire quickly and then stop abruptly, you could end up at a margin that’s between two images.

 

It’s then possible for the margins to not be the nice whole numbers you expect (0, 300, 600, etc.), but instead be slightly off. So you need to be less specific. If the slider is at the beginning, the left margin will be equal to or greater than 0.

 

Similarly, if the slider is at the end, the left margin will be less than or equal to the endMargin (less than because the values are negative, remember). Go ahead and make that change:

var isAtBeginning = function() {
return getLeftMargin() >= 0;
};
var isAtEnd = function() {
return getLeftMargin() <= endMargin;
};

When you now run your slider and press an arrow key rapidly, you’ll see it’s impossible to get past the beginning or end. There is one more problem, though: it’s possible for the index that’s displayed to briefly be too high or low. 

 

You have images 1–9, but the index will briefly get to 0 or 10 as you hit the left arrow too quickly. Can you spot the source of this bug? It’s in the animateSlider() method:

var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=" + imageWidth }, settings.duration, callback);
var increment = (direction === "+" ? -1 : 1);
updateIndex(currentIndex + increment);
};

 

Here, you are updating the current index immediately after the animation is kicked off. Instead, you should be updating the current index once the animation finishes, so you should be doing it within the callback.

 

By doing this, you ensure that once the animation is done, the index is updated as you expect. This also means the index is only updated when the animation runs through to a finish. You need to refactor your animateSlider() method, so update the index within the callback.

 

Once you do that, you can call the callback that is passed into the animateSlider() method. This shows your refactored animateSlider() method:

var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=" + imageWidth }, settings.duration, function() {
var increment = (direction === "+" ? -1 : 1); updateIndex(currentIndex + increment); if(callback && typeof callback == "function") {
callback();
}
});
};

 

Within the callback, you can update the index, and then call the passed in callback. Be careful here because you first need to check that the callback is set to something, and that it’s a function. A quick conditional does that for you. With that, your slider is much improved and the bugs have been squished. Good work!

 

Summary

What a blog! You created your very own image slider—complete with automatic animations and keyboard shortcuts—from scratch. You’ve made it robust and versatile by clearing animations properly and calculating all values mathematically, rather than hard-coding any of them.

So that you can admire your work, here’s the full slider plug-in:

(function($) {
$.fn.slider = function(options) {
var defaults = {
duration: 1000,
animationDelay: 5000
};
var settings = $.extend({}, defaults, options);
return this.each(function() {
// store some initial variables var $slider = $(this);
var $sliderList = $slider.children("ul");
var $sliderItems = $sliderList.children("li"); var $allButtons = $slider.find(".button"); var $buttons = {
forward: $allButtons.filter(".forward"),
back: $allButtons.filter(".back")
};
var $index = $(".index");
var imageWidth = $sliderItems.first().children("img").width(); var endMargin = -(($sliderItems.length - 1) * imageWidth);
var totalImages = $sliderItems.length;
var currentIndex = 1;
var isPaused = false;
var animateSlider = function(direction, callback) { $sliderList.stop(true, true).animate({
"margin-left" : direction + "=" + imageWidth }, settings.duration, function() {
var increment = (direction === "+" ? -1 : 1); updateIndex(currentIndex + increment); if(callback && typeof callback == "function") {
callback();
}
});
};
var animateSliderToMargin = function(margin, callback) { $sliderList.stop(true, true).animate({
"margin-left": margin
}, settings.duration, callback);
};
var getLeftMargin = function() {
return parseInt($sliderList.css("margin-left"), 10);
};
var isAtBeginning = function() {
return getLeftMargin() >= 0;
};
var isAtEnd = function() {
return getLeftMargin() <= endMargin;
};
var updateIndex = function(newIndex) {
currentIndex = newIndex;
$index.text(currentIndex);
};
var triggerSlider = function(direction, callback) { var isBackButton = (direction === "+"); if(!isBackButton && isAtEnd()) {
animateSliderToMargin(0, callback);
updateIndex(1);
} else if(isBackButton && isAtBeginning()) { animateSliderToMargin(endMargin, callback); updateIndex(totalImages);
} else { animateSlider(direction, callback);
}
};
var automaticSlide = function() {
timer = setTimeout(function() {
triggerSlider("-", function() {
automaticSlide();
});
}, settings.animationDelay);
};
var timer = setTimeout(automaticSlide, settings.animationDelay); var resetTimer = function() {
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(automaticSlide, 30000);
}
$allButtons.on("click", function(event) {
resetTimer();
var isBackButton = $(this).hasClass("back"); triggerSlider((isBackButton? "+" : "-")); event.preventDefault();
});
$(document.documentElement).on("keyup", function(event) { if(event.keyCode === 37) {
resetTimer();
triggerSlider("+");
} else if (event.keyCode === 39) { resetTimer();
triggerSlider("-");
}
});
});
}
})(jQuery);

Recommend