What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
jQuery-free JavaScript
by Elijah Manor
Do you need jQuery? Let's look at some common jQuery code snippets and rewrite them with native browser APIs or micro-libraries.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
When to Use jQuery?
Course Introduction
Hello, my name is Elijah Manor, and this course is called jQuery-less JavaScript. You can find more about me at my blog at elijahmanor.com, and you can communicate with me on Twitter @elijahmanor. Before we proceed with the course, I build off basic jQuery and JavaScript concepts. If you feel that you don't know those fundamentals, then you might consider watching either Dan's jQuery Fundamentals course or Liam's JavaScript Fundamentals course. Many of us started using jQuery because it ironed out many cross browser issues, it was easy to use, and it had a consistent API. However, web browsers these days continue to get better and better, and are following web standards much more closely. Do we still need jQuery? Has it become a crutch? Can we get away with dropping jQuery as a dependency and using native browser APIs instead? In this course, we'll explain when it's appropriate to use jQuery and when you could go without it. If you do decide to go with jQuery, then there are other courses you could watch at Pluralsight to help you along. However, if you decide to go jQuery free, then that's what the rest of this course is about. We'll show jQuery snippets throughout the course and show you how you could write those equivalent snippets without jQuery. First, we'll start looking at selectors and how to find and iterate over elements in the DOM. Then once we've grabbed the elements in question, we could start to manipulate them by changing classes, attributes, et cetera. Then we'll change our focus on how to add event listeners to elements, user proxy, and trigger events. Next we'll look at how to make AJAX calls without jQuery. We'll also talk about how to make a JSONP request. Then we'll take a look at various handy jQuery utility methods and show how we could get the same functionality. We'll look at concepts such as data, each, grep, map, extend, and type checking. Next we'll talk about how we could use CSS animations to replace some of the common jQuery animations. A benefit of using native CSS for animations is that it performs much better than its jQuery counterpart. And finally, we'll conclude by looking at jQuery plugins and talk about how we can make a plugin that doesn't require jQuery, and look at a technique to wrap your code to become a jQuery plugin if that's the functionality you need. Along the way, we'll be looking at the sample RSS reader jQuery application and slowly convert it to a jQuery- free application. At the end of each module, we'll move away from the slides and touch on the things we've learned by applying those concepts to the application.
When Should I Use jQuery?
So, let's get started with module 1. This module is entitled When to Use jQuery? When should I use jQuery? Yes, that is a very meaty question. You may or may not have heard those in our community encourage you to use native features of the modern browser instead of using jQuery. The idea is to cut off the fat of a bloated library when much of it isn't needed. It turns out there are a lot of factors to evaluate when making a move like this. The aim of this module is to give you some direction and insight on things you should consider before making a decision to use jQuery or to not use jQuery. So let's get started with some good reasons why you should use jQuery. If you're making a quick proof of concept or a prototype for a website, then using jQuery to quickly get out of the gate might be a fine idea. The caveat to this is that sometimes prototypes or proof of concepts become the final product. So if you eventually want to not use jQuery, then that could be an issue, or at least something to think about. If you're already using jQuery plugins and depend on them, then that's another good reason to use jQuery as well. You could possibly find non-jQuery versions of your plugins, but that might be difficult and the quality you'll find may be hit or miss. Also, jQuery UI Widgets and the Twitter Bootstrap components all require jQuery. So if you want to use any of them, you'll need jQuery for sure. In addition, if you're using a library or framework that needs jQuery, then obviously you'd need jQuery. For example, Backbone.js and Ember.js both use jQuery under the covers. We'll talk a little bit more about this later in this module, but for now let's just say you'll need jQuery in those cases. The last point we'll consider of when you might want to use jQuery is if your lowest common denominator browser cuts the mustard or not. What does that even mean? Well, you need to think about what the barest bones browser you want to support. What features must it have in order for you to continue with your technology stack? Back in March of 2012, the BBC blogged about a decision they made to use a small snippet of code to determine if the browser in question is sufficient for the JavaScript experience that they desired. Here's the snippet of code. BBC wanted the browser to support querySelector, which is a way to get elements from the DOM, to support localStorage for persisting data, and to support addEventListener, which supports DOM level 2 events. As it turns out, requiring these features basically includes all modern browsers except IE8 and older. Why not IE8 you ask? Well, although IE8 does have querySelector, it only supports CSS selectors up to 2.1. IE8 also does not have addEventListener, so you'd have to use the attachEvent method instead. IE8 doesn't support dispatchEvent, so you'd have to use the fireEvent. IE8 doesn't support the new XMLHttpRequest2 or FormData. You could still do AJAX, but it isn't as elegant and straightforward. IE8 actually does have support for JSON parts, which is good. However, you need to make sure IE8 is in standards mode for it to work. For example, if you don't have a doctype, then IE8 goes into quirks mode, which is not good. IE8 doesn't have the matches DOM method, which allows you to test a CSS selector against a current element. Actually there are no browsers that support the matches method, they're all currently prefixed and use the old name of matchesSelector. So you'll find this in modern browsers under msMatchesSelector, mozMatchesSelector, and webkitMatchesSelector. IE8 doesn't support ECMAScript 5, which includes a lot of nice array methods such as a filter forEach, map, reduce, and a whole bunch of other things. IE8 also doesn't support classList, although either does IE9, so in that case we'll need to use a polyfill. There's a way to do this manually, but as you'll see later, you probably don't want to do it. And finally, IE8 doesn't support CSS animations. However, IE9 doesn't support CSS animations either, so that's something we'll have to talk about in a later module. But all in all, I hope that you can see if we drop IE8, then the browser world looks much better. If you do need to support IE8, then I'd recommend that you just go ahead and use jQuery because it has patched over a lot of these concerns for you, and you don't have to think about them or use special tricks.
Custom Builds of jQuery
So, what if you do decide you want to use jQuery after all? Is there a way to make your experience even better? Well, yes there is. Depending on what features you use, you may or may not need all of jQuery. That is and has been a concern for a very long time. Some people want jQuery to be as small as possible, and others want it to have more and more features. And actually one of the reasons for why some people don't want to use jQuery is because its size versus the value they feel it gives them. If jQuery was smaller and provided what they needed, then it still might be a good fit for them, which leads us to custom builds of jQuery. As of jQuery 1.8, you can create custom builds of jQuery. However, jQuery doesn't provide these custom builds already configured for you, so it's up to you to figure out what pieces you want included and build yourself. There are two main ways you could create a custom build of jQuery. One is to pull down the source from GitHub. The process isn't very hard, but there are several steps that you'll need to follow, and we'll uncover these in just a minute. There is another way to make a custom build of jQuery, and it's using an unofficial jQuery Builder website. It's essentially just a GUI around the command line build process that we're about to look at. But providing a GUI can be appealing to many who would rather not use the command line, or just don't want to set up their local environment to build jQuery. Thankfully, the process isn't very hard, although there are several steps that you'll need to follow. So let's take a look at building it ourselves. Thankfully the process isn't very hard, but there are several steps that we'll need to follow. Before you start building jQuery, you'll need Node and Git installed on your machine. There are numerous ways to do this on both Mac and PC, so I'll leave that part up to you. However, once you have Node and Git installed, you could open up your terminal and then type git clone git://github.com/jquery/jquery.git, and that will go out to GitHub and download the jQuery repository locally on your computer. At that point, you could type npm install --g grunt-cli bower. Once you'll install the grunt command line interface to help you build jQuery and also the bower package that assists with pulling in front-end libraries, then to make sure both grunt and bower are installed correctly, you can type grunt --version && bower --version. If those are installed correctly, then you could change directories to the jQuery folder and install all its necessary dependencies by typing cd jQuery && npm install. That'll take a little while, but when it's done, you could type grunt and that will go and start the default build for jQuery. So far you've just made a normal build of jQuery, so now we could refocus and talk about custom builds. So before we go and make a custom build of jQuery, let's talk about modules. JQuery is organized into modules when it's being developed in GitHub, and then the build process pulls them together in order to make the final JavaScript file that you use in your browser. We could choose to not include one or more of these modules so that jQuery will not include it in its custom build. As you can see, there are modules for AJAX, CSS, dimensions, effects, events, and much more. If you don't use a particular part of jQuery and size is a concern for you, then you might consider making a custom build of jQuery without those pieces. Once you've determined which modules you could live without, the next step is to tell grunt which modules you want to exclude. As we've already seen, you can run in grunt to make a normal build of jQuery. For this example, the un-minified output was almost 9000 lines of code for the whole library. Now if we tell grunt that we want a custom build, and to remove the AJAX, CSS, deprecated, dimensions, effects, event/alias, offset, wrap, sizzle, and exports/amd, whoa, then the end result will be a library that is slightly over 4000 lines of code. Okay, that might have been a little overkill on excluding modules, but I think you get the point. The above examples were using the master branch, which is probably not what you want to use for a custom build. You usually want to base your build on some known build version. So this example shows how you could use tags in git to pull the version that you want. By typing git checkout tags/2.0.3, we can pull the 2.0.3 version of jQuery. Then, npm install to make sure we have all the dependencies, we'll perform a normal grunt build, and then you can make your custom grunt build, passing the modules that you don't want to include. It's important to note that jQuery has slightly changed the syntax of some of their modules. For example, event-alias is now event/alias. And also the master branch has a lot more modules that you could exclude whereas older versions didn't have as many options. So the tip here is to consult the readme.md file for instructions about what modules can be removed and their corresponding names. For those of you who aren't as comfortable with a command line, would rather not set all that up or you're just in a hurry, you could use the unofficial jQuery Builder website to make a custom version. This is a nice graphic user interface where you could pick the version of jQuery that you want, and then the screen changes to show the appropriate modules that are available to exclude for your version. Then you just click the build button to download your custom version. You could also use cURL from the command line or install one of its custom command line tools if you want, but you don't have to. There are other options you could use such as curling from the command line or using their custom command line tool, but those are just alternative ways to do the same thing.
Alternate Libraries
One other thing to consider is possibly using another library instead of jQuery. Maybe you don't want to go without jQuery completely, but you just want something with a similar API, but very much lighter. Well thankfully there are some options for you here. And on a side note, if you're using a library like Angular.js, then you don't need jQuery either because they have an internal component called jqLite, which is a mini version of jQuery that just does the things that it needs. But enough about that, let's redirect to alternate libraries. So a while back, Thomas Fuchs came up with a library called Zepto.js. You may or may not have heard about it, but it's essentially a smaller version of jQuery with a similar API. There are features that aren't included, which is why it's smaller, but for the most part it contains the pieces that you'd want and need. When it comes to a mobile application, I've heard of many who use Zepto because of its lighter footprint. As a side note, Zepto was an option before jQuery released its module custom builds in version 1.8. The Backbone.js website mentions that they require a dependency on either jQuery or Zepto, which is pretty interesting. One thing to note is that Zepto doesn't support Internet Explorer 6, 7, 8, 9 or 10 because it modifies __proto__, pronounced dunder proto for short. But interestingly enough, IE11 does support dunder proto, so you should be able to use it then. Another even smaller library written by Remy Sharp is called Min.js. It's a very minimalistic library that somewhat mimics the jQuery API. As you'll see in the upcoming modules, some of the syntax that I'll show you is more verbose than in jQuery version. So using a library like min.js can help reduce a lot of typing and make your code more terse. Additionally I wanted to mention an Experiment Dolla project that Burke Holland and Leland Richardson put together. It's a small recreation of the jQuery API that they put together as they wrote an article on TekPro. It's a good learning resource and shows some of the things that they had to think about and consider along the way.
Demo
Before we mention about certain features and certain browsers and how we made a decision of using IE9 and above, well how did we determine that? A good tool to use is caniuse.com. We could come in here into the search box and type classList for example, and we could easily tell that classList is not supported in IE8 and 9, but it is 10, 11, and pretty much most other browsers and versions. This helps us to determine that we probably need a polyfill for IE9 to support this if we want to use classList. Another example might be localStorage, and thankfully it's supported pretty much everywhere, which is really great, even in IE8. We could also look at something like querySelectorAll and we can notice it has really good support. However, if we look down in the notes, it'll give us some more interesting information such as the IE8 implementation is limited to the CSS 2.1 specification. Another nice one is the matches, which we'll talk about later. It's not actually supported fully anywhere, but it's partially supported lots of places using the old name of matchesSelector instead of the new name matches. It's also vendor prefixed with the old name, such as msMatchesSelector, webkitMatchesSelector, et cetera. So this is a really good tool just to kind of figure out where everything's at, and if we need certain polyfills to fill in the gaps. Next thing we want to look at is Zepto.js. We mentioned this is this really small library that is jQuery-like in its API. You'll notice on the left a lot of these look very familiar. If we come over to addClass for example, well that's in jQuery, you just say addClass and provide a string. Or you could provide a function that will determine what the class will be. And then we'll come over to Remy Sharp's Min.js, which is a very small library, but it feels very much like jQuery. You can select things of the DOM using the dollar sign, you could add event handlers with the on method, and you can loop over things with the forEach method. If we come in and look at the distribution, it's really small, it's only 69 lines of code. And again, so it doesn't provide a lot for you, but it helps make your code a lot more terse, and so if you want to simplify things a little bit, you could use Min.js. So here we're going to build a custom version of jQuery. First, you need Node installed and Git, but once you have those installed, you could just say git clone git://github.jquery/jquery.git. And that'll go and clone jQuery from the repository up in GitHub, pull it down to your box, it doesn't take too long, and now we have it. So then we need to make sure that we have the grunt command line interface installed and bower. So we could say npm install --g, for globally, and we want the grunt-cli, and we want bower. And that'll go out to npm, download those packages and everything they depend on, which is quite a bit. It'll take a just a second, but once those are down then we'll test to see if they're loaded correctly by saying grunt --version && bower --version. And sure enough, they both came back with a version number. So now we're going to go inside of jQuery and we're going to npm install, which will look into that particular repository and figure out all the packages that it needs, and it will install them. And so here it's going out and it's getting everything it needs. So now we're good. And then we could just say grunt, which will actually make the very first build of jQuery with all the components listed, all the modules listed, it'll go and build them and uglify them and make them into a nice little bundle, so now it has combined all the modules, made a jQuery.js and a jQuery.min.js. If we look at the folders, it actually created a dist folder, and we look in here and we can see that it created the jQuery.js, jQuery.min.js, and a jQuery.min.map, which has a source map file to help you actually debug through the minified code if you want, and Chrome has that feature right now. So that's pretty cool. So what we can do now is we can make a custom version of jQuery, and let's say we just want to take out the AJAX module and maybe the CSS module. So it'll take those two modules out, build the rest, and then give you a new version. So we could go back into our dist and here are our new files and they're a little bit smaller than they were before, so that's good, but really we're working off the master branches, which is probably not what we want to do. So, what we could do is we could say git checkout tags, and each version is tagged with a particular number, which is the version that has been released. So let's check out the 2.0.3 version of jQuery, and now it's saying that we're now at that release, and then we'll say npm install, because different versions might actually have different dependencies. So we're just going to say npm install just in case it needs things that we didn't have earlier. And once that's done, we'll do a normal grunt build just to kind of kick everything off to make sure everything is set up. And then once that's done, then we'll actually run our custom command. Alright, there we go. And now we can actually make our custom grunt build. And here say we don't want AJAX and we don't want CSS. And again we'll go out and just pull those modules, make a new version, and put it in our dist folder. And now that version will be the 2.0.3 version without the AJAX and CSS modules, whereas before we had just done it off the master, which is like the latest and it's not actually fully baked and not ready for production yet, but this version with the tag should be ready to go. And if the command line isn't for you, then there's a nice unofficial jQuery Builder website that we could use. Here we'll actually grab the 2.0.3 version like we did before, and we'll remove AJAX and CSS and you can actually see the file size getting smaller of what the end result will be. We could actually choose to have a minified version or not, and then we could say build, or we could actually pull this from our command line or actually install another module, but we're just going to click the button. And here it actually gives us this file, so we could just then save. And so here we could save this version as jquery-ajax-min, showing that we removed those modules and it's minified, and we could save it somewhere and start using it in our application, or we could rename it or whatever we want to do. But this is a much nicer alternative to having to work with the command line and installing all these things and not being familiar with that process.
Summary
So, as a summary, does your website cut the mustard? If you recall, that essentially means are you using Internet Explorer 9 and above and other modern browsers? If the answer is yes, then you may be able to do without jQuery. However, if the answer is no, then using jQuery is probably a good idea since there are a slew of features that aren't supported in IE8 compared to other modern browsers. If you still do end up using jQuery, which is totally okay, then maybe you could consider making a custom build of the library to only include the modules that you need or use. You do this either from the command line, or there's an unofficial website where you can do this. And if that's not small enough, then you could consider using Zepto.js, which mimics the jQuery API, but it's much more streamlined. However, it doesn't support Internet Explorer at all. Or, you could possibly use a barebones utility library called Min.js, which provides some helper convenience methods if you decide to use native browser APIs.
Native Selectors
Introduction
Hello, this is Elijah Manor. In this module, we'll focus on how to natively grab elements from the DOM and navigate around. This module, and others to come, will first show a snippet of jQuery code, and then we'll look at one or more additional snippets that will perform the same action, but without using jQuery. As I touched on in the last slide, the whole idea of selectors is to eventually find something you're looking for in the DOM. Typically we want to pinpoint either one element or a group of elements so that we could perform some action on them.
Selectors
So let's first focus on various ways you would select elements using the jQuery library. You could select by ID using the pound syntax, you could select by tag name or by class name, and you could also send in a complex CSS selector, which really all the other examples are doing as well. Now when we move to not using jQuery, or jQuery-free, we have several options we could choose from. We could use the getElementById method off the document. This method turns out to be super quick in comparison to all the other examples we'll see. You could also use the getElementsByTagName, which will only get elements that match the tag name you provide. There's also the getElementsByClassName method, which actually only came out in IE9. So you should be fine as long as you're not supporting IE8 or below. And the most powerful option is querySelectorAll, which works very similar to jQuery in that it uses a CSS selector to identify a set of DOM elements. There's also querySelector, which is just like querySelectorAll, but it only returns the first element that it matches. I typically use getElementById, querySelectorAll, and querySelector.
Each
Once you've selected the elements from the DOM, a common thing to do is to iterate over them. JQuery has a very familiar each method that you can invoke off the jQuery object after your selection has been made. If you didn't want to use jQuery, you could instead use the querySelectorAll method and then kick off a native for loop, incrementing an index and using that to access each item with a bracket notation. As it turns out, there are several other ways to do this that are much cleaner, so let's take a look at those as well. Another option to natively iterate over DOM elements is to use the forEach array method in ECMAScript 5. However, querySelectorAll doesn't return an array, what it does return is a node list, which unfortunately does not have forEach as one of its methods. What we can do though is access the array slice method and pass in the node list to convert it to a real array. Once you have the array, you could forEach over it and access it that way, which is pretty nice. However, that might seem like a little bit of extra work to iterate over the node list. Another way that I prefer better is to create a new array and call its forEach method, invoking the call method and pass node list as its context. This ends up being a little bit cleaner, and also gets the job done. Don't worry, we're not done yet, there's yet another way. So even that last example seems like a lot of work. What you can do is create a helper function to make things a little bit cleaner. In this case, we have a helper method named $$, and it accepts a selector and internally does all the weird code of calling slice, passing the node list, et cetera, and returns the converted array from the function. The end result is something that feels very similar to jQuery, but is still pretty close to the medal. If you do go jQuery-free, then you might want to consider making helper functions like this, or use the Min.js library or one of the others I mentioned near the end of module 1.
Index
Another thing that sometimes happens is that you've already retrieved a group of elements from the DOM, but you're only interested in one of the elements in the middle. You're probably already aware of how to do this in jQuery, you could either use the eq method, the get method or the bracket notation and pass the index. Here we're getting the element at index 3. It's good to note that the eq method gets the jQuery wrapped element, whereas the get and bracket notation get the raw, unwrapped DOM element. The jQuery-free techniques are very similar in nature. If you were to use querySelectorAll for example, you could use the item method or the bracket notation like above and grab the element at index 3.
First and Last
Now that we know how to find the index, a common helper method in jQuery is getting the first and last element from the internal jQuery collection. In jQuery, you could call the first method, or you could pass the zeroth index to the eq method to change jQuery's internal collection to only include the first element. Or as we saw in the last slide, we could even use the get method or bracket notation and get the first raw DOM element. To get the last item, you can call the last method, or you could pass -1 to the eq method to change jQuery's internal collection to only include the last element. Or you could pass -1 to the get method or figure out the last index and pass that to the bracket notation to get the last raw DOM element. In a similar fashion, if you didn't use jQuery, you could still use the bracket notation that you get at the first element, or just use the querySelector method, which only gets the first match anyway. If you wanted the last item, then you could pass the last index to the bracket notation, or you could call the pop method off an empty array and pass your node list to the call's method's context. Either way, you will get the last item.
Is
Once you have an element, sometimes it's handy to know what type of element it is. There's a handy method in jQuery called is that lets you pass a selector and test if it matches against the current element. The result is either true or false. As it turns out, it's pretty easy to do natively as well, all you do is call the matches method off the element and pass a selector just as you would with jQuery's is method. However, there is a problem. No browser currently supports the matches method, but many of them, including IE9 and above, support the vendor prefixed MatchesSelector method. So, I'm using a polyfill to provide the official matches method, which then in turn maps to the correct vendor prefixed method. This polyfill can be found at manor.im/jquery-free-repo.
Filter
Again, once you have a group of DOM elements, the next step might be filter them to a smaller subset. In jQuery you could use the filter method and pass another selector, which will reduce the internal collection to whatever matches that selector. You could also pass a function to the filter method. JQuery will loop over each item in its internal collection and invoke your callback. If you return something truthy, then that element will remain in the internal collection, but if falsy, that item will be rejected. If you took a jQuery-free approach to this, you could convert the node list to an array and just use the ECMAScript 5 filter method. To mimic the first overload of the jQuery filter method, you could use the matches method off the element to match the selector. And again, I'm using the polyfill I mentioned previously. In the second example where we pass a function, it's very similar to the jQuery version. If we return something truthy inside, then we want to keep the item, and if we want to reject it, we just return something falsy. The filter method returns a new array, which is a little different from what jQuery was doing before. JQuery was using the filter method to modify what was inside of its internal collection.
Find
Sometimes you also need to search for elements from within those that you've already matched. To do this, you would commonly use the find method off the jQuery object and pass the selector that you want to find. For this example, we're finding the main element and then we're searching for input elements with the date class underneath that element. If you've already grabbed several items from the DOM, then you would also call the find method in jQuery and it would iterate over those items and search under each one to build up a new internal collection. Here we found all the divs on the page, and then we looked for all input elements with the date class underneath those divs. To do the equivalent thing natively, you could just call querySelectorAll off the element you've previously matched. Here, we've grabbed the main element and then passed the input date selector to querySelectorAll. That will give us a node list containing all the input elements with the date class. Things get a little bit more tricky if you want to find elements from a node list. The above jQuery example looks just as easy, but jQuery is doing quite a bit under the covers for you. To do this natively, we could write some code like the following. Here, I'm grabbing all the divs with querySelectorAll, and then I'm looping over them, and for each div, I call querySelectorAll again, and then I can concat those matched elements onto an inputs array that will contain our final result. Yes, that's quite a bit of code, but it does get the job done. Hopefully you're starting to appreciate what jQuery provides you, and this might encourage you to possibly use a small helper library for things like this, but it's not necessary, it's up to you.
Next and Previous
Sometimes the element that you have is close to where you need to be, but not exactly. In jQuery, it's really easy to move to the next or previous sibling node using the prev and next methods. Likewise, natively you could use the previousElementSibling or nextElementSibling property off the element in question. Thankfully this is pretty straightforward and the code is pretty simple.
Closest
Navigating to siblings is good, but sometimes you need to navigate up the DOM looking for a specific ancestor element. There is a parent method in jQuery, but I tend to use the closest method instead since it's less brittle. The way you call closest is to pass a selector and jQuery will first check the current element to see if it's a match, and if not, it will navigate up the DOM tree testing each element until it finds a match, and then it returns that element in the jQuery collection. Unfortunately, there is no closest method that we'd use natively, but here is the through process behind it. We find the element where we want to start, and then we start a loop and test each element to see if it matches our selector. If it doesn't match, then we'll grab the parent node and try again until we find a match. This is a little cumbersome, but as we'll see in the next slide, there's an easier way. So writing all that code each time would be cumbersome, and it was a little naive, so here's a little script to add this functionality to the element's prototype so that it's handy whenever you might need it. Once included, you could use it pretty simply as seen here at the bottom. We're using getElementById and then we're calling closest, passing the selector to match. In case you'd like to look at it further or use it in your project, the script can be found at manor.im/jquery-free-repo.
Demo
So here's the web application that we're going to look at for the rest of this course. It's a simple little RSS reader that will pull in the articles from Tech.pro. Here's the articles on the left and here's the details on the right. So if we click on one of these articles, it'll swap out the article and show it here. We could filter the articles, so we're going to just show the JavaScript ones that are tagged with JavaScript. If we untag it, then it will show them all again. So what we're going to do is go over to our code, we're going to use brackets, which is a free IDE made by Adobe, and here we have a blog library. We have its posts, categories, and we have a channel that we could publish and subscribe to. Inside of its init, we're actually kicking off the call to go get the posts, it'll use a JSONP call, and then we're subscribing to a bunch of messages that posts have been updated, displayed, and filtered, and will react accordingly. And then we're listening to a couple of user events when someone clicks on one of the items, the posts on the left, or when they click one of the filters on the top. The get post kicks off a getJSON jQuery call, which is really a JSONP request. And we're using YQL since it's a cross domain concern, and Yahoo is actually getting the RSS for us and bringing us back using JSONP. And so here you can see select * from rss where url is tech.pro.com/rss/blogs. When we get the data back, we'll actually map over it, which we haven't really talked about yet, but we'll essentially do a little changing to the categories and then we'll publish that we have got the new posts and then other people are listening to that event and will respond accordingly. We have display lists, which essentially is pulling out a templating library, we're using underscore, so it's getting the template, looping over the posts, building up markup, and then eventually just shoving some stuff in the DOM. And then it's triggering that the posts have been displayed. We have some other code like setting the default value of which is selected on the left pane. So if it's the very first time it's loaded and there's no active post highlighted on the left, then it will pick the first one, and if it's been filtered and maybe the item that was selected gets hidden because it's filtered, then we'll actually figure out what to display. Here we're changing the post, so depending on what they actually click will change the activity correctly and will call displayPost passing the URL. ChangeFilter just goes through all the posts and makes sure they match according to the filter that they've clicked on. And what we're actually going to change is this filterList method, just a teeny bit. Unfortunately we haven't talked about too much for us to change. If we went and changed every selector in here a native selector, it would break quite a few things since we haven't really talked about how to wire up event listeners and things like that. So we can't just change them all because jQuery kind of relies on the on method to behave with a jQuery object. So we'll wait until the next module before we start changing lots of stuff, but we can change just a little bit in this filterList. So here where we were selecting list-group-item, let's actually use a native selector for that. So let's come up here and declare some new nodes and we'll say document.querySelectorAll. And then what we'll do is we'll pass this selector, and we can use the exact same one, it's a class selector, and that will actually return us nodes, which we're not using yet, but nodes will be a node list. And unfortunately a node list does not have forEach on it, which is one of the ECMAScript 5 methods. But what we could do is we could new up a new array and we could say forEach, and then we could call the call method, which allows us to actually give some context to the loop. And so we're kind of tricking forEach to kind of really use our stuff even though it's not implemented, which is kind of cool. And so what we'll do inside of the function here is we'll tell it that we're looping over the node, so it'll give us access to the node. And just so everything works, what we're going to do is wrap our node with jQuery so that the rest of our code will work. Later when we talk about more things like testing for things inside of arrays and accessing data and adding/removing classes, we'll change up quite a bit of this code, but for now we'll just save this and we'll re-run it to make sure it still works. And sure enough, everything's working, filtering is working. But later we'll come in and change even more of this. And then the very last thing is displaying the details so when they click on an item on the left, it will actually update the title and the description on the right. So that's it for now. There's actually lots to change, unfortunately we hadn't learned too much at this point actually to start changing some things, but soon once we learn about event handlers and native loopings and manipulation and all those other things and animations, we could start changing more and more things.
Summary
So, as a summary, with jQuery you could select an element or elements by using a CSS selector using the jQuery function. Likewise in jQuery-free land, you could also use the querySelectorAll method that's off the document object. This method also takes a CSS selector and is available in modern browsers. Once you have a list of elements selected from the DOM, you could use jQuery's each method to iterate over them, or you could use the native array for each method to iterate over the node list returned from querySelectorAll. However if you recall, there's no forEach method off a node list, which is why we're using the array's forEach and passing our list as its context. When you have a list of items in the jQuery internal collection, sometimes you want to access just one of them. To do that in jQuery, you could use the eq method and pass the index of the item that you want. To do this with a node list, you could use the square bracket operator and reference the index of the item that you want as well. If you want to test if the item you've selected matches a specific CSS selector, you could use the is method in jQuery, or if you have the raw DOM element you could use the matches method that we've polyfilled. If for some reason you've selected too many elements, then you could use jQuery's filter method to reduce the list to a smaller subset of items, in this case based on a CSS selector. If we wanted to do that with an array of elements, then we could use the native array filter method and return the result of the matches polyfill method. However, let's say that we have one element and that we want to search for items underneath it. In jQuery, you could use the find method to do that. Without jQuery, you could call the querySelectorAll method off a raw DOM element to do the same thing. The end result is a node list. If you wanted the next sibling of the element with jQuery, you could call the next method, whereas you could access the nextElementSibling property off a raw DOM element to do the same thing. Lastly, if you wanted to navigate up the DOM looking for an element that matches a selector, then you could use the closest method in jQuery. Likewise, you could also use the closest helper method that I showed earlier in this module to do the same thing. So, that's it for this module.
Native DOM Manipulation
Introduction
Hello, this is Elijah Manor, and this module covers DOM manipulation. We'll show how to manipulate the DOM with jQuery and then how you could do the same thing with native browser APIs. DOM manipulation is a common task in most any web application. We're either creating elements or modifying them all the time. Maybe we're adding a class or changing a style or adding new content. These are things that are necessary for a very interactive web app.
Classes
For example, manipulating classes on an element is a very common task. With jQuery it's very easy. JQuery provides addClass, removeClass, toggleClass, and hasClass methods to help you manage this. Adding is pretty straight forward, and it allows you to add several classes at a time. ToggleClass is pretty handy and smart. If the class is present, then it'll be removed, but if it isn't there, then it will be added. And hasClass is a nice way to let us know if the class is already applied to the elements or not. Things are a little more complicated if you decide to not use jQuery. In IE9 and older you would need to somehow manipulate the className property off the element. It would be up to you to concatenate to the property or somehow manipulate it with a regular expression or a fancy index of string manipulation, which is probably something you don't want to be doing by hand. Thankfully, there is a classList standard that's implemented in most other browsers and IE10 and above. ClassList looks very familiar to the API that jQuery has. There's add, remove, toggle, and contain methods. Thankfully, you could polyfill for classList if it doesn't exist in your browser, which is what I recommend for IE9. You could grab it at https://github.com/eligrey/classList.js. As you can see, the browser support is pretty good, except for IE9, which is why I recommend using the polyfill.
HTML and Text
A common thing that you'll need to do is to replace the text or HTML of an element. You could do this with jQuery using its HTML and text methods. If you call the methods without an argument, then they're a getter, and if you provide a string as an argument, then they're a setter. Going to jQuery-free isn't too hard at all in this case. All you have to do is access the innerHTML and innerText properties off the element, and then you could either read them as a getter or assign to them as a setter, and that's all.
Append and Prepend
It turns out that appending and prepending with jQuery is pretty easy. There are prepend and append methods where you pass some HTML markup and jQuery will create the elements for you and insert them into the DOM. When you move to native APIs, you have to do a little more work. You'll need to manually create the elements you want to insert in the DOM, manipulate their properties, in this case we're updating the inner text, and then you could call the insertBefore or appendChild methods. Coding for this could get somewhat cumbersome as your markup gets more complex. For example, if we wanted to create a table, we'd need to build up each element, table, TRs, TDs, et cetera, and assign their relationships to each other manually before finally inserting the table into the DOM.
Remove
Sometimes instead of hiding something from the DOM, we want to actually remove it completely. In jQuery this is pretty easy and there are several ways we could do it. You could call the empty method, which will wipe out the innerHTML of that element, you can explicitly set the innerHTML to an empty string by calling the HTML method or you could call the remove method off the jQuery object. Without jQuery, you could do some of the same types of things. You could set the innerHTML to an empty string, you could create a loop and continually call removeChild, deleting the last child property until they're gone or you could grab the element's parent and call removeChild on the element.
CSS
Usually you'll want to focus on changing style by adding or removing CSS classes to and from an element, but there are cases when you might need to actually update the style attribute on the element itself. In that case, you'd want to use the CSS method that jQuery provides. You could either pass in the style name as the first argument and the style value as the second argument, as demonstrated here, or you could actually pass in an object to the CSS method, and jQuery will iterate over the object and/or use the keys as the style names and set them to their corresponding value. A couple of things to notice here. If you want to use the CSS name as you'd author in a CSS file, then you could use the dashed version, or you could actually use the camelCase CSS property name as you'd find in the JavaScript API. However, if you do use the dash name, then you'll want to make sure you add quotes around it when adding it inside the object. If you decided not to use jQuery, then the process is very similar. There is no CSS method, but you can change the styles by manipulating the properties off the element style object. Here you only use the camelCase CSS names instead of the dash versions like you could with jQuery's CSS method. You could also use the bracket notation to access the properties of the style object as well. By doing so, you can make your code more dynamic by passing in the key names and values to a function. So if we wanted, we can make a helper function to take our element and an object, much like the jQuery CSS method, and iterate over the object applying its keys and values to the style object. If this is handy, you might want to pull this out into a helper library, or something like that.
Attributes and Properties
Now let's talk about accessing and changing attributes and properties for a minute. Historically, jQuery only had one method to do this, the attr method. But as of jQuery 1.6, it introduced the prop method as well. The main distinction is that the attr method is meant for attributes, and the prop method is meant for properties off the DOM element. Properties are dynamic and don't update the corresponding attribute when changed. For example, the placeholder is an attribute that you could read and write to, but let's consider the checked property on an input field. Once the user checks the input box, if you asked attr the value of checked, it wouldn't reflect that it's been checked by the user, you'd need to use the prop method instead to test for that. Another interesting distinction is if you check the href with the attr method it will give you the relative path, or whatever you provided as the href in your markup. But if you used the prop method instead, it will give you the fully resolved path, which you may or may not want depending on your circumstance. When we look at the native version of getting and setting attributes and properties, the jQuery code starts to make a little more sense. Here we have setAttribute and getAttribute methods, and also corresponding properties of the element that we could check and assign. Likewise, we get the same behavior when we access href, either by getAttribute or the href property. Since these concepts map over pretty well, there isn't much of a learning curve, which is nice.
Value
If you're dealing with form elements at all, you'll typically need to read or set the values of those fields. With jQuery, there's a val method. If you don't pass an argument, it'll get the value and if you pass an argument to the method, it will set the value. Likewise, if you don't use jQuery, there's a value property that you could either read or set by assigning something to it, and that's all.
Height and Width
Manipulating height and width is actually considerably complex inside of jQuery. If you open up the source code, you'll see that it's doing a lot of things to make it work correctly. If you look at the image on the right, you'll see that there are a lot of factors to consider, like margin, border, padding, and the original dimensions. JQuery has some methods to assist you here, like width, innerWidth, and outerWidth. When you move to the non-jQuery land, there are properties you could use as well, such as clientWidth, offsetWidth, and you could call the getBoundingClientRect method and get its width. If these techniques get you the value you need and it works for your application, then great. However, you might have to provide some extra logic depending on how your element is positioned or styled. Just keep that in mind. Just for kicks, let me show you how non-trivial the jQuery source code is. I don't expect you to understand all of this, but just be informed of how many edge cases there are, and we're not actually seeing all the code here. There are other methods that are called from within here too. The main takeaway is that you could try clientWidth, offsetWidth, and the like, but if they don't work right away you might have to dig a little bit deeper.
Demo
So here's the application we'll be looking at. It's an RSS reader for Tech.Pro Blog. The articles are here in the left. If you click on one, it'll update here on the right. And here's some categories you could filter by, here we're only looking at the JavaScript articles, and then we could unclick it to go back to our original list. So let's take a look at our code and see what we could change based on the things that we learned in this module. Let's search for TODO and what we're going to do here instead of use jQuery for the selector, we're going to use document.getElementById, because we know the ID, it's blog-post. And instead of using the HTML method, we'll use the innerHTML property. We'll come down here and we'll do the same type of thing, we'll use the innerHTML property and assign it to HTML, and here instead of using getElementById, we don't know the ID, but we do know the class, which is list-group. And we know there's only one, so we could use querySelector, in this case, it's just like querySelectorAll, which selects multiple things, but querySelector will only give you the first one. So that'll give us back the element and we could set its innerHTML. We'll come down here to the setDefault. We'll do a couple similar things. We will say document.querySelectorAll this time, that'll give us back a node list, and we'll take off the dollar sign. In jQuery land, a lot of developers will prepend variables with a dollar sign to indicate it's a jQuery object, but in this case we don't want a jQuery object. So let's just take the dollar sign off of all these active variables, and then what we'll do here if it didn't find anything, and then we're going to actually grab the item that should be selected. So we'll say document.querySelector, singular, because we want the first one that we match. And in this case, we'll take off colon first, that's actually not supported as a standard CSS selector, that's something that jQuery has added as a custom pseudo-selector that it understands. But in order to get the first one, we could just say querySelector, because that gives us the first one anyway. So we'll pass that to setActive and we'll pass this to displayDetail. Instead of using the attr method, we'll just use the href property off the element. And that should be good for that method. We'll come over here to setActive. And what this does, it's grabbing all the items that are active, all the group items that are active, and removing the class. Now technically there should only be one that's active at a time, but we're going to assume that maybe there's more. So we're going to say querySelectorAll, give us back that node list, and if we want to iterate over the node list, then we could say forEach, and then could say call, and we could pass our nodes as our context, and then we'll give it a function to iterate over and we'll tell it that node is our property there. And then what we could do is come in here and say node.classList.remove active. And so that will remove the active class from all the nodes inside that list. And then in here, we're passing in an element that's going to be a raw DOM element. And we'll come down here and instead of addClass, we'll say classList and we'll say add. Now if you remember, classList isn't supported at IE9. If we come over to our browser and look at html5please.com and type in classList, it'll actually list this feature and it tells us that we need to use a polyfill most likely if we want to use IE9 or less. And so we could click on this, go to this repo of eligrey, either pick the un-minified or minified version, grab the raw version, and just save this to our project. Now we could have used caniuse.com and actually look at classList and we'll see the support across all browsers, and here we see IE10 and 11 have it, but 8 and 9 don't. So this is just a nice couple of tools to get an idea of what features are supported. Alright, so we did that. So let's go into this changePost method and we'll change this around just a little bit. In here what we're going to do is we're going to just take off the dollar signs and just deal with the raw DOM elements. In here instead of the attr method, we're going to just call the href property. And the last thing we're going to do down here is change this to document.querySelector and we will set this to the innerHTML. And then down here we'll do the same thing. (Typing) There you go, that should be all the changes that we will make this time around. Next module we'll change more things near the end. The reason we didn't actually change the classes here is because we're chaining some animation and we haven't talked about animation yet, so we'll refactor that later. And again, some of the other methods, utility methods we'll talk about in a later module, and data and each and things like that. We'll refactor some of those later. So let's go back over to our code and make sure things still work. Sure enough, everything loaded up. We could change posts, we could filter them, and everything still works.
Summary
So, as a summary, in jQuery once you've selected an element, it's really easy to add a class using the addClass method. Likewise, if you had a DOM element, you could use the classList API and call the add method. This is only supported in IE10 and above, so you'll want to use a polyfill. A common thing that you'll need to do is to update the HTML of a particular element. In jQuery, you could use the HTML method and pass a markup, whereas if you're using a native DOM API, you could use the innerHTML property. In addition to updating the current element, you could also insert new elements into the DOM. An easy way to do this with jQuery is to call the append method, passing new markup. Or, without jQuery you could create an element with document.createElement, manipulate it, and then call the appendChild method, passing in your new element. After adding a new item in the DOM, you might want to remove it. With jQuery, you could just call the remove method, and without jQuery, you could call the removeChild method off the parent to remove a certain element. If you want to change the style of an element in jQuery, you could use the CSS method, passing the style name and value. The native way to do this is to change the properties off the style object. In order to change a property of an element with jQuery, you could use the prop method and pass the name and value, kind of like you would with a CSS method. And the native version of this is just to access the property of the same name off the element object. It's a pretty common thing to have form elements on your website, and because of that, chances are you'll need to access the value of one of those fields. In jQuery, you could use the val method to access the value, and without jQuery, you could just access it using the value property. Finally, getting the width of an element is pretty common as well. There are several ways to do this jQuery, but one of them is the outerWidth method. Natively, you could use the offsetWidth property, but you might find that this doesn't give exactly what you need. You'll need to make sure that this gives you what you need, and if not try another technique instead.
Native Events
Introduction
Hello, this is Elijah Manor, and in this module, we'll be talking about events. We'll look at how to manage events in jQuery, and then we'll look at how we can provide the same behavior without using jQuery. Events are a crucial part of most web applications. At some point or another, you'll need to interact with the user somehow, either if it's to respond to a button click, their scroll position or keys they're typing.
Bind and Unbind
There are several ways in jQuery to add an event listener to an element. Here we can use the click event helper method and attach a callback, or we could use the bind method and pass the event type of click and provide a callback as well. Additionally, we could also use the on method, passing click and the callback much like we did with the bind method. That might seem like a lot of ways to do the same thing, but there's a little bit of history behind all those decisions, which we won't go into right here. Anyway, that's jQuery. The previous example showed code when we had selected just one element, the element with ID of save, but it's just as easy if we had selected several items from the DOM, like the following example. Here we're selecting all the buttons on the page and adding a callback when they're clicked. Behind the scenes, jQuery is looping over each element in its internal collection and adding the click event handler to each one. If we switch over the native way, we could use addEventListener and provide the event type and a callback to be invoked when the event occurs. So here we're grabbing the element with ID of save, and then adding a click event handler using the addEventListener method. Now that seems pretty straightforward, however, once you want to add event handlers to a group of items, the code isn't as elegant as the jQuery version. Here we have to loop manually, whereas jQuery did it behind the scenes for us. So, we're finding all the buttons on the page and looping over them and adding a click event handler to each of them. You might notice that we're attaching the same callback for each of the items instead of creating a new one. So if we want to unbind our event handler, we could use the jQuery off method. You could also use the unbind method as well, but it's just a one line statement to call the off method. There are several overloads you could use with the off method. If you don't provide any arguments, then it will remove all the event handlers for all event types. If you provide just an event type, then it will delete all event handlers of that type. And if you provide a namespace, then it will only delete event types that match your namespace. And you could also remove just one event handler if you have a reference to it. The above code samples work if we only have one element selected in our jQuery object, or if we have selected a collection of elements. In order to unbind a native event handler, there aren't as many options. JQuery really does provide a lot of functionality, but with native we pretty much only have removeEventListener and we need to provide both the event type and a reference to our callback. If you selected a group of elements, then you'd have to loop over them and call removeEventListener individually. Again, this is much easier in jQuery because it does that loop under the covers for you.
Delegate and Undelegate
There are actually other ways to add event handlers in jQuery other than the three ways I've already shown. You could also use the delegate method and the three parameter versions of the on method. The behavior of these two are the same in that they're attaching metadata at some point higher in the DOM, and react to a triggered event. If an event happened that matches their criteria stored, the selector and the type, then our event handler will be invoked. So the above examples are selecting the container element and storing some special information on it, a selector, an event type, and an event handler. If an item is clicked on underneath the container that matches the widget selector, then our callback function will get invoked. If we don't use jQuery, then we could call the addEventListener method, and inside the callback, we could check to see if the target of the event matches the selector that we're concerned about. And again, we're using the matches method, which is polyfilled for IE9. If the target is a match, then we'll execute whatever code we intended inside the if statement. Unfortunately, there's an issue with the last native solution that we just saw. If the item we clicked on is a child of the selector we're trying to find, then there won't be a match. So, we could do something like this instead where we try to match what was clicked on and then grab its parent to test it until we go all the way up to the element where the event handler was attached. So in this example, we add an event handler to the container, test the element that was clicked on, and climb up the DOM, testing each element along the way until a match is found, or we reach the container. If a match was found, then we could execute whatever code we want. Yes, this is quite a bit more code to do something that jQuery made very easy. We could clean this up somewhat by using a helper method. I've pulled this code out into a closest helper method and included it in the jQuery-free repo so that you could simplify your code to something that looks like this. Here we just call the closest method off the target and we optionally provide the implicit this parameter to let the method know when to stop looking at the DOM. If we didn't provide this second argument, then it would have navigated all the way up the DOM tree until it hit the document or until it found a match. When it comes to undelegated with jQuery, you have lots of the same options that we saw earlier. Here you could say off to all event handlers for everything, or you could be a little more specific and limit our destruction to only a particular selector in event type. We can get specific and also pass an event handler instance that we attached previously. Or we could say remove all namespaced event handlers as we did before. When it comes to undelegated native, it's the same as we saw before. We need to call removeEventListener on the parent node that we were using to watch the DOM. Since the matching logic was in the event handler itself, we don't have to worry about that.
Prevent Default and Stop Propagation
If you click on an anchor or submit a form, then sometimes you'll want to prevent the default behavior of the browser, either redirecting or posting to the server. The process is exactly the same in both jQuery event handlers and native event handlers. You call the preventDefault method off the event passed to the handler. You could also prevent the event from bubbling up the DOM tree by calling this stopPropagation method. This is also the same with both jQuery and native techniques. As a side note, in jQuery if you return false from an event handler, it's converted to mean both preventDefault and stopPropagation, which you may or may not have wanted. So I usually recommend not using return false and instead explicitly saying what you meant in code. It also helps other developers know what you really meant to do.
Target and Which
Another thing that's the same in modern browsers is the target and which property is off the event object. Whether you use jQuery or the native addEventListener, you'll get access to the target of the element, the element that was interacted with, and access to which, which is the key that was pressed if an event was keyboard related. Which is a newer property, it came about as a normalization between key code and char code when they were across browser differences. However, if you're using IE9 or above, then you don't have to worry about such concerns.
Proxy
By default, the this implicit parameter in an event handler is the element that triggered the event. In this case, it was the search button that we clicked on. If we want the this context to be something else, then we could use the jQuery proxy method as shown below. Here we're telling jQuery that we want the this context to be the store object once we get inside the event handler, which enables us to read the category property when building the URL variable. Without using jQuery, the process is pretty similar, but we don't have the proxy method available to us, but that's not a problem because ECMAScript 5 has a bind method that behaves in a similar way. Here we tell addEventListener to use the store clickHandler method and to bind this context to the store object. And now this will work just the same as the last line.
Trigger
Once you have all these event handlers in place, sometimes it's nice if you could programatically trigger them instead of rely on the user initiating the events. In jQuery, you could do this by calling the trigger method off the jQuery object, you provide the event type and optionally any data that you want to send along with the event. In this case, we're triggering the click event on the tab element, once with no data and a second time passing two additional arguments. You can do something very similar with native APIs, but it looks a little bit different. First you set up your event handler with addEventListener. If you want to create an event that has no additional parameters, then you just create a new instance of event with the type of event and then you call the dispatchEvent method passing your event. If you do want to pass along some data, then you create an instance of CustomEvent, tell of the type of event, and then provide your custom data. And then just like before, you pass your event to the dispatchEvent method. And as you can see here, the detail information that we sent along with our custom event is available off the event object on the detail property.
DOM Ready
In jQuery, it's common to put a bunch of code in the DOM ready event handler. You'll commonly see one of the following options, either wrapping the document and providing an event handler in the ready method or passing a function to the jQuery function, which behaves as the ready event handler. If you don't want to use jQuery, you could just put all your scripts at the bottom of your page right before the end of the body element. By that point your DOM will be fully intact and your JavaScript can safely manipulate it or you could subscribe to the DOMContentLoaded event using the addEventListener method. You might consider this technique if for some reason you can't put all your code at the bottom of your page.
Demo
So here's our sample application again, it's a simple RSS reader that's reading from Tech.Pro. And here are the blog posts on the left. If we click on one, then it pulls up the details, and here's a filter list up here that we can click JavaScript and it'll just show us the JavaScript items. If we unclick, then it will show them all again. So let's take a look at our code and see what we could change based off what we've learned. Before we get too far, let's look at the bottom. I actually pulled in some resources that we've been talking about recently. I pulled in classList, which is a polyfill, because IE9 does not support that. We're pulling in matches, which is a polyfill, because most modern browsers actually support this feature, but use the old name and use the vendor prefix. So this will polyfill the new name. And also there's a piece of code that I had shown in an earlier module called closest, and that mimics what jQuery does. Natively that's not supported so I included it here. It also added a custom script called button-group. And what we're going to do here is we're going to comment out bootstrap.js because it depends on jQuery and we're trying to eventually get rid of jQuery. So let me save this and we could take a look at what button-group does. It's just a really simple piece of code. It's based on how bootstrap kind of works, it's looking for HTML5 attributes of data-toggle, and if it's set to buttons, then we're going to grab and loop through the items, add click event handlers, and toggle an active class if they click on it or not. So this enables us to get rid of bootstrap because that's all we really needed it for, at least the JavaScript file. So let's go back over to our script file, and what we're going to do is we're going to go through here and look at all the TODOs and refactor those to use native JavaScript instead of jQuery. We'll still have some jQuery stuff in here, but as we proceed through the other modules, we'll slowly start removing all of it. So we're going to use the Postal.js message bus, which is written by my friend Jim Cowart. And so up here in our globals we're going to say postal:false just to let jslint know that it's okay to see postal. So instead of using the document in jQuery as our mediator, we're going to say we want to use postal and we want a new channel. And that's the way postal works. And so in here when we use postal for our channel, we'll say we want to subscribe to a particular message instead of saying on. So we'll just copy this, replace it over, that on and this on and this on, and all the rest stays the same. So here we're actually responding to user events. So we're going to say document.querySelector, and that will grab the list-group element, and then we'll say addEventListener. Here, since this was using the three parameter version of on, which is akin to delegate, so addEventListener doesn't work that way so we're going to have to take out the anchor and somehow manually account for that inside of our callback, and we'll do that here in a minute. But first let's change this one as well. This will be document.querySelector, and then we'll have to add addEventListener. And then we'll have to take out the input and somehow account for that inside of the callback. And so we'll do both of those here in a second. So let's go look for changePost. Here we go. And so in here we'll take off the TODO. So what we'll do in here, so now we're at a higher level where we're attaching this event handler, so we want to look at the event target to kind of what has been acted upon. And so whatever they clicked on, we want to look for the closest anchor tag. So it could be the thing that we actually clicked on, so closest would first check the thing that it is. So whatever you clicked on, is that an anchor, yes or no. If it is, it'll return it, if not it'll go to its parent and check it. Are you an anchor or not? If not, it'll keep going up to its parent until it reaches this second argument, which is the location where we attached the event handler. So it'll keep going up the tree until it hits the location where the event handler was stored. And then we'll save that off as post. And so if that does exist, then we want to do all this rest of the code. If it doesn't, then we just don't want to do any of it. So that's good for that one. ChangeFilter is a little bit tricky as well. We're going to put the e in there so we can look at the target. We'll actually remove a lot of that code, we don't need it. What we're going to do here is save off a node array, kind of initialize it, and then we'll check to see if the event target matches an input element. And so this one we're listening for the change event, so if they have actually clicked an item, that changes the input checkbox, then we want to make sure that this code happens. So if that really did happen, if we checked a checkbox, then we want to grab this, which is the location higher in the DOM where the event handler is attached, we want to actually look for all other checkboxes, including the one that was checked on. And what we're going to do here, is there's some metadata on each checkbox saying what category it pertains to. So it's that bar up top where it says JavaScript and CSS. We want to filter the articles based on what they've checked. So this code is figuring out what checkboxes there are and then we'll figure out what categories are actually selected, and then we'll filter the posts based on what they've selected. So what we'll do here is we'll put all this code inside this if statement, and I'm not going to refactor a lot of this code right here, we haven't got to some of the concepts yet, so what we'll do is instead of inputs we will wrap our nodes that we just got. And jQuery is smart enough to take a node list and to convert it into the internal jQuery collection that it has. So that should be sufficient for that. So let's check if we have any other TODOs, and sure enough we do. We'll come in here, instead of trigger it's called publish, and so we'll publish this piece of code. Let's copy this because we'll need that later. And we'll delete that. And when we pass arguments, we don't have to put it in an array like you would have to if you use jQuery's trigger. And here we'll delete this. The interesting thing is if you did use jQuery trigger, it always sends an event object, but when you use postal it doesn't have to do that, which is nice. So you just take that e off, we'll take this e off, and we'll come in here, take off the array syntax, remove TODO, and then we'll make this publish and we'll see if there's any other TODOs. So we should be done, let's make sure that's saved. We'll go back over to the index, make sure that looks alright. Okay, that looks good. So we should come back over to our code, refresh, we get all our articles, we could click on them, change them, we could still filter them, which is great. And so now we've removed quite a bit of jQuery, but there's still quite a bit left. If you look and go back to our script, there's still quite a bit. If we look for dollar sign, we still have our AJAX, we have some utility methods like map and each, map again, we're using data and is, and some other things like that. But don't worry, we'll cover those concepts in modules to come.
Summary
So, as a summary, it's pretty simple to wire up an event handler with jQuery, you just select the element that you want and then call the on method providing the event type and a callback method to be invoked when the event occurs. And thankfully, IE8 and above and other browsers allow a similar syntax using the addEventListener method off the document object. You also pass the event type and a callback method. jQuery also provides a three parameter version of the on method that delegates listening to an element higher up in the DOM tree. In this case, we're letting the main element listen for click events on any element that matches the button CSS selector. We could do something similar with native DOM APIs, but it requires a little bit more code. Here we're attaching an event handler to the parent element, main, and then we're testing the event's target, looking for its closest button. If that was found, then it matches what we want, so we'll handle our logic there. A nice feature that jQuery provides is the proxy method, which allows you to change the this implicit parameter inside the event handler when it's invoked. By default, it's the DOM element in question, but in some cases you'd like it to be something else. In this case, we could ask jQuery to let it be the store object. Without jQuery, it's actually not very difficult either. You could use the ECMAScript 5 bind method to get the same behavior. Here we're passing the store object to the bind method. And finally, once you've set up all these event handlers, it can be nice to programatically trigger one of these events. In jQuery, you could call the trigger method and provide the event type that you'd like to simulate. Without jQuery, you could new up an event object, passing the event type, and then call the dispatchEvent method off your element with the event. And that's that.
Native Ajax
Introduction
Hello, this is Elijah Manor, and in this module we're going to talk about making AJAX requests. JQuery does a really good job at making AJAX requests easy, so we're going to review what it looks like in jQuery, and then we'll look at how to make AJAX calls natively. AJAX has actually been around for quite a while. Internet Explorer introduced the technology back in 1999 with IE5. Since then, it's been adopted and modified by other browsers as well. In this module, we'll take a look at get and post requests, as well as JSONP.
Ajax Get
In order to make a get request, jQuery has a nice get helper method. You pass in a URL for the request, optionally provide it data, and then a function to call back when the response arrives. Due to the same origin policy, the protocol, domain, and port of the URL need to be the same as the requester's location. Instead of calling jQuery's get helper method, you could instead call jQuery's low level AJAX method. The idea is the same, but the syntax is a little different, and there's a lot more options to control. You pass an object to the AJAX method and inside of it you could pass things like the URL, optional data, what type it is, a success callback, an error callback, and lots of other things. If you don't want to use jQuery, you could instead new up an instance of XMLHttpRequest and call the open method providing the get verb, a URL request, and an optional async flag. Then you provide an onload callback that'll be invoked when the response comes back from the server. And finally, you kick off the request by calling the send method. All in all, not too bad.
Ajax Post
In a similar fashion, jQuery has a helper method to make a post request. You call it the same way as before, you provide a URL, optional data, and then a callback. And like before, we can call the low level jQuery AJAX method to make a post request. JQuery will make sure to send the data provided in the appropriate way, depending if it's a get type or post type. Without jQuery, you still need to create a new instance of the XMLHttpRequest and open it like we did before, but this time we tell it we want to POST. In addition, we set the request header to indicate that we're passing some form data. We setup our onload callback, and then when we kick off the request by calling send, we could pass along some additional data. A nicer way of sending along post data is using the formData object. You could build up the data you want to send by appending new keys and values, and then passing the formData as the parameter to the send method. An important note is that IE9 does not support formData, so if you want to use this technique, you'll need to use a polyfill. Another nice way of using form data is that you could pass it a form element from your page, and it will append all the appropriate keys and values for you. And then all you have to do is pass the formData object to the send method like we did before.
JSONP
A common technique of requesting information from another server is to use JSONP, which allows you to get around the same origin policy. JQuery makes this type of request look as if it were a real AJAX request, but it's really not. All you have to do is provide a dataType of JSONP, and the rest looks like it's just any other get or post request. In the same way, if you used the getJSON helper method and provide a callback URL parameter, then jQuery will wire up all the special JSONP pieces for you and it'll just work. So what's really going on then? Well it's easier to see if you don't use jQuery. If we want to make a JSONP request, then what we have to do is create a new script element, set its source to some remote source, and insert it into the DOM, we set the callback URL parameter to a function we have on our page, and we wait for the server to respond. Now, an important note here is that the server will have to notice that we're sending a callback parameter and it will need to wrap its JSON data as a parameter to our JSONP callback function so that when the response comes back, it'll invoke our function and we could handle it appropriately. So, as you can see, jQuery is doing a lot of trickery for us, but it looks like it's just a plain old XMLHttpRequest, but it's very much not.
Micro-Library
So all of this might be a little too much for your taste. Another alternative is to use a micro library to handle your AJAX requests. If you're going to use one, I recommend using the Request library if you'd rather not use the low level XMLHttpRequest. This tiny library is very rich and supports a lot of the nice features that jQuery has, but without all the other modules that you might not need.
Demo
Alright, here's our application again. And what we're going to do this time is we're going to swap out the jQuery AJAX call, actually it's using a JSONP request, and we're going to change it to use a native form of the JSONP request, which is kind of interesting. So let's come over here and look at the $.getJSON and this special callback=? is a special thing that jQuery recognizes and does all the JSONP magic. And of course the server that we're talking to, the Yahoo API, has to understand this as well, and they do. So what we're going to do is we're going to replace the question mark with a function of where we want it to go when it's done. So we're going to say blog.jsonCallback. And of course we don't have that defined yet, so let's say blog.jsonCallback. And we'll make a new function and we'll pass the data into that function. And so what the server will do is it'll see that we're expecting blog.jsonCallback to be invoked with some data, and so that server will get all the data that it needs, and then before it ships it over, it'll actually surround the data with blog.jsonCallback. So it's kind of invoking our method, but shoving its data inside as a parameter. So once it gets to our side, since we're going to create a script tag and imbed on the page, it'll actually invoke the response and we'll have this magic method waiting for us and it'll get invoked passing the data, which is really cool. So we'll keep all this same, this URL, and then the next thing we'll do is we'll have a script and we'll actually create a new element, createElement, and then we'll create a new script tag. And most all this, we'll take this out, we don't need that anymore, and we'll put this in our special function. And then up here what we're going to do is set the scripts source to the above URL. And the last thing we're going to do is grab the document.head and we're going to append a new child and we're going to append our custom script. And we can actually delete this, save it off. So once we've injected the script in the head, then it will actually go make the request to Yahoo server, then it will actually go and get the RSS feed, get all the data back, surround the data with blog.jsonCallback, and then it will come to the page and be evaluated, and then it will notice oh, well I need to invoke the jsonCallback method, and hey, it's right here, and I want to pass the data that they sent me. And then I could just do all the rest by itself. So I'm not actually going to refactor this piece of code yet, we'll reserve that for another module, but the rest of it should just work. So, let's come back to our browser and we'll refresh, and sure enough, we got all the data and we're using our custom JSONP request that we're wiring up manually, we're not actually using jQuery at all right here. And so that's all you have to do, it's kind of weird. Of course this is a JSONP request, if it was a real XMLHttpRequest, then it would look differently, but that's what we talked about in the slides.
Summary
So, as a summary, jQuery makes it really easy to make AJAX calls. For example, you can call the get method, pass a URL to the request, and a callback method to capture the response. To do this natively, it's actually not that difficult either. You new up an XMLHttpRequest object, open it with a get verb and a URL, provide an onload callback, and then send the request. Making a post with jQuery is actually just as easy as the get. Here we're calling the post method off the jQuery object, passing a URL, some data, and a callback method. In order to do this natively, it isn't as straightforward or as nice. We still need to do as much code as we did before, but now we need to set the request header and make sure to send the data formatted in a special way. I did show a cleaner way to do this with formData previously, but if you don't want to use a polyfill for that, and you'd like a simpler syntax without having to use jQuery, then I recommend using a micro library called Request. It enables you to have a much more terse and full-featured experience like you're used to with jQuery.
Native Utilities
Introduction
Hello, this is Elijah Manor, and this module is about utilities that are helpful when making web applications. We'll look at helpful jQuery utilities and then show how these are also available natively, and if they're not, we'll talk about using a micro library instead. Once you've retrieved data from the server, you need to do something with it. It's handy to have a set of utility methods to make manipulating data easier. In addition, you'll probably find yourself needing the same type of code over and over again, which is where utility methods can come in handy.
Data
We'll start with jQuery's data method. If you add an HTML5 data attribute to an element, you could use jQuery's data method to retrieve the data, or you could use the attr method. With the attr method, you have to provide the full attribute name, such as data-contact-name, and a string value will always be returned. If you use the data method instead, you drop off the data, remove the dashes, and camelCase the key and jQuery will return a value of the appropriate type, a string, a number, array, an object, et cetera. So here when we ask for options we get the value in object form. Behind the scenes, jQuery converted the JSON string to an object for us. Another way to use the data method, which has actually been around before HTML5 data attributes, is to just get and set rich data onto the element. Here we're attaching an object under the data key of a person. If we wanted to get that object back out, then we just call data again, passing the key of person. Now when we go native, there isn't a rich way to get and set objects, but we could manually parse strings and objects if we need to. Here we're using the getAttribute and setAttribute methods off an element to manipulate HTML5 data attributes. You'll notice that we're using the full name of the attribute, data-contact-name. If we need to store something richer, we could use JSON.stringify to serialize an object to a string in order to save to the attribute, and then we could use JSON.parse when pulling out the JSON string to convert it back into an object. There is another way we could get and set HTML5 data attributes, and that's with the dataset object. Using this technique, you could use the short camelCase version of the data attribute to get or set its value. Here we're changing the HTML5 data attribute, data-user, by setting contact.dataset.user. You could only provide data set string values, so if you need a richer data type, then you could use JSON.stringify or .parse to convert a string to and from an object. Unfortunately, dataset is not available in IE9 or IE10, so you'll need to provide a polyfill if you want to use this feature. You could find one at manor.im/polyfill-dataset. Instead of using this feature, you can just use getAttribute and setAttribute if you want.
Map
The next utility methods we'll look at are each, grep, and map. These are very common methods that I use quite often when developing a web application. We're going to use the following data here as we exercise these utility methods. Here we have an array of languages with an id, date, and by attributes. The each method is a way to iterate over an array. You pass the method in an array and a function that you want to be invoked for each item. In this example, we're just logging a message to the console. The grep method is a way to search or filter only for a subset of items in an array. You provide the original array, and then a function that you want evaluated for each item. If the function returns something truthy, then that means you want to keep that item, and if you return something falsy, then you want to reject that item from the resulting new array. The map method is a handy way to transform what each item in the array looks like. Here we're calling the map method, passing in the original array, and much like the other methods, a function that will be invoked for each item. Whatever you return from this function will represent what that item looks like in the new array. So this is a nice way to change property names, trim down a huge object, possibly manipulate values or add new ones. In this case, we only wanted two properties in our object, a name, which is the ID of the original object, and an age property, which is how old the language is. The end result is something that looks like this, an array of three items, only the ones that had the string script in their ID attribute. And each object only has two properties, name, which was the ID previously, and a new age property, which is how old the language is. If you don't use jQuery, then the transition is pretty easy because ECMAScript 5 has new array methods that map to each method. There's a forEach method for looping, a filter that will serve as our grep, and a map method, just like we had before. The way we pass the function and use it is just the same as the last slide, but overall it's a little bit cleaner because we don't have to pass in the array since we're calling the methods off of our array. And the end result is the same as before, we get an array of three objects with names and ages. There is another option you could have taken with this. Instead of using the ECMAScript 5 array methods, you could have instead used the underscore or low dash, each, filter, and map methods. Since we're using IE9 and above, I would go for using the native array methods, but if you needed to support IE8 or less, then underscore or low dash would be a better fit. You could have used an ECMAScript 5 polyfill, but since I tend to include underscore or low dash anyway for other reasons, I'd rather just use one of those instead of using a polyfill. And if you need top performance, you might actually get better results using low dash anyway. However, it's really up to you and what you feel comfortable with.
Extend
The next helper utility we'll look at is extend. In jQuery, this is a very common thing to do when making a custom jQuery plugin. It's often used to merge options passed from the developer with a default set of options that the plugin author setup. You pass the target as the first argument and the object or objects you want to merge as additional arguments. The end result is a merged result of all the objects together. The end result in this case is a new object that has color of Chartreuse and the default font of Tahoma. The code to actually do this is not trivial, and there's not a native method in JavaScript to do this for us. So here's where having underscore or low dash is very helpful. You could end up using the method in the exact same way as you would with jQuery, so that's good.
In Array
Sometimes you want to know if an item is in an array or not. JQuery has an inArray helper method that you could use. You pass the item you want it to look for as the first argument, and you pass the array to look in as the second argument. If the item is found, the method will return the index at which the position it was found. Otherwise, it will return -1 to indicate it was not found. If you want to convert that to a falsy/truthy value, then you could use the tilde bitwise operator trick, and in this case I'm also converting that to a Boolean using the double bang trick. A non-jQuery way to do this is to use the ECMAScript 5 index of method off the array and pass the item you want to look for. The return value is the same as jQuery's in array in that it's an index or -1, so I'm using the same tilde double bang technique. As a side note, there are lots of other methods in underscore and low dash dealing with arrays and collection manipulation. I highly recommend you looking into one of these libraries.
Type Checking
Since JavaScript is dynamic and loosely typed, it's often helpful to know what type you're dealing with. Thankfully, jQuery has a nice type method that can tell us what type of a variable we have. There are also some other helpful methods like isArray, isFunction, and isNumeric. If we move over to not use jQuery, then we could use the typeof operator in JavaScript. However, it doesn't always give us the information that we hoped we'd get. For example, an array comes back as an object when it would have been nice to know if it was an array. Thankfully in that case we could use the native ECMAScript 5 Array.isArray method, or you could also use underscore or low dash isArray method for example. In many cases, typeof should work for you, but it's nice to know your options.
Trim
The last utility method we'll look at is trim. Whenever you take input from the user, you probably should consider trimming the results. Trim just takes off the beginning and end whitespace that usually isn't intended by the user. JQuery has its own trim method, and also modern browsers, including IE9, supports the trim method off the string. So that's a very easy alternative.
Demo
Alright, here's our sample application again. It's a simple RSS reader for the Tech.Pro Blog. Here we have our articles on the left, we can click on one, it'll pull up the details on the right, and we have a filter, so we can say, give me all the JavaScript items, it'll just give me those, and then I can take off the filter. So let's take a look at our code and we'll refactor some of things that we've talked about in this module. Before we start, let's actually look at our index.html. I pulled in the polyfill for the dataset so that we could use that. So we'll come back over to our scripts and then we'll just go through all the TODOs and slowly go through and change these out. So here we'll come in here, instead of map, there's a native map that we could use, and it's off the actual array. So we could take that and we could move it over and replace the dollar sign. So it's the same name, map, and everything just kind of works, so that's pretty cool. And let's come back to another TODO. We'll delete the TODO. And then here we're doing an each. Now this one's a little interesting. So we're going to grab the array and we're going to replace the dollar sign, and this one's forEach, so it's not actually just the each, it's forEach. And the other tricky thing is the difference between the jQuery's utility each method and the native one is the callback. In jQuery, it gives you the index first and then it gives you the item it's iterating over, whereas the native one gives you the item it's iterating over first and optionally you could actually have an index. So sometimes that's a little tricky when you're converting. So let's go to the next one. And here we have a map. And this one's a little interesting because this is actually a node list from a previous module and we're actually shoving it in jQuery to wrap that. So we're going to have to do something a little bit more clever. Here we're going to use the empty array, we'll say map, we'll say call, and then we'll pass in our node list. So this is kind of the similar trick that we've used in past modules when we did a forEach on a node list. And then in here we'll call it node, so we're looping over our node list, so this would actually be an element, a DOM element. And then we'll come in here, we'll change this up. So instead of checking is off of this, which is now just the node, we'll just say hey, is that checked at all? We'll actually use the property instead of using that method. And then down here for the data, there's actually two places in our code where we're accessing HTML5 data attributes. In one of them we'll use the getAttribute method, and in the other one we'll use the dataset polyfill that we pulled in. So in this one let's use the getAttribute, getAttribute and then we'll have to give it the full name, which is data-category, and that returns a string to us, so we're good there. Now we could actually get rid of the get because before when we were using jQuery, we were allowing jQuery to do this mapping for us with the jQuery collection, and so if we wanted to get the data out, like the raw internal array out, that's where you have to call get, but we're actually dealing with an array now, so that's good. The other thing we have to do, which is kind of weird, is there's a slight difference on how map works between jQuery and the native map. In the jQuery version of map, if you return something that was null or undefined, then it essentially kind of rejected that item and didn't include it in the file array, whereas the native map doesn't behave that way. If you return null or undefined, then that will actually be that entry in your array, which is a little bit different than filter because filter, you know, if you return something false then it will be rejected, but maps is a little different. So what we have to do here if we want to use this technique, it's a little strange, we're going to filter the array that came back and then we're going to return a Boolean of whether it is null or not. So essentially that will kick out all the entries that really shouldn't have been there in the first place and only give us the items that really are pristine categories. Alright, so that should take care of this one. So we'll go over here and so we could take this categories array and we can move it over to our forEach, or we're going to make it into forEach. We're converting the jQuery each with a forEach. And remember the important thing is to take off this index, because that will mess us up. So the next thing we'll want to do is use the dataset to access the categories. And so in this case, we're going to look at the node and its dataset, and we're going to grab its categories, which happens to be a serialized array. And so the nice thing with the data method in jQuery is it will look at the data and try to figure out what type it thought you meant, and then it would give you back a rich type. So we're actually going to JSON.parse this because we want to pull the array out so that we could use it. And here, we're actually trying to figure out if our category is inside of our tags array, and we're using the inArray method of jQuery, but thankfully we could just call tags and there's an indexOf method that's native now, and we could just say hey, we want to know if the category is inside the tags. So that will convert that. Now the other interesting thing is the each helper that jQuery had, if you return false out of it, it was kind of a short circuit, it gets out of the loop early, whereas in our case the native forEach doesn't do that, that's not supported. So let's change this to another method called some. And the way some works, it's a native method as well off the array. What some will do is it will go through, you still provide a function, so it'll take this function and invoke it for each item in the list, and if one of them returns true, then it's like oh, I found what I need and it won't continue on anymore. So what we're going to do here is we're going to just return the fact if we found the item or not. And then we'll save this off and say hey, we found it or we did not find it. So if it comes through and eventually returns something that's truthy, and we'll go ahead and make this a Boolean, if it returns something truthy, then hey, it did find it. But if it never did find something, it will keep looking and if it didn't find it, it'll be false. So this is a way we could kind of short circuit out of the array so we're not necessarily having to look for everything all the time. The other thing we have to do before we get out of this, actually we could take out this, we don't need that anymore, and we still have to make this work down here. So what we're going to do is, so we kind of broke this now, we're just going to wrap the node that we're looping over and put it inside of jQuery so this other code could work. We're eventually going to refactor this when we get to animation, which is the next module, but for now we're just going to leave it as is. Alright, I think that's it for that particular method. So let's go another TODO. This one's real easy. Now there's no grep natively, but there's another function that does the same thing, it just has a different name, it's called filter. And that should work just fine. And that should get us what we want. So we'll come back over here and we'll refresh. Sure enough we could click between the articles, we could filter, and we can un-filter. And there we go.
Summary
So, as a summary, if you need to access HTML5 data attributes with jQuery, you could use the data method. Or if you don't want to use jQuery, then you could use the native dataset API with a polyfill. There are several array jQuery utility methods, such as each, grep, and map, that can be very helpful. But you could also use the native forEach, filter, and map methods instead. If you've ever made a custom jQuery plugin before, then you've probably used the extend method. It's helpful when overlaying custom options onto a default set of options. Unfortunately, there isn't a native way to do this, but you could use a micro library such as underscore or low dash to provide a shim for you. Sometimes it's helpful to see if an array has a particular entry. In jQuery you could use the inArray method, but natively you could also use the indexOf method off the array. You might have noticed that many jQuery methods are overloaded. Well, JavaScript doesn't actually support method overloading, as you might be familiar in other languages like Java or C#, but you can mimic the behavior by making the function check the number and type of arguments that are passed to it, and then respond accordingly. JQuery provides the type method to make the task of type checking easier. If you wanted to do this natively, then you could use the typeof operator and the new Array.isArray method. Lastly, when you take input from the user, it's usually good practice to trim any proceeding or trailing whitespace. In this case, jQuery has a handy trim method that you could use. Natively there's now a trim method off this string that you could use as well. And that's that.
Native Animation
Introduction
Hello, this is Elijah Manor, and in this module, we're going to talk about web animation. Browsers have come a long way when it comes to CSS. We're going to take a look at several animation techniques using jQuery, and then we're going to compare how to do the same thing with CSS only.
Vendor Prefixes
Before we proceed with examples, I wanted to mention that I'll only be showing standard CSS properties instead of adding all the vendor prefixes. There are many techniques you could use to add these prefixes later. You could add them by hand or use one of these tools listed here, like --prefix-free, Prefixr, Autoprefixer, Compass for Sass or Nib for Stylus. Whatever you do use, it is important to add them somehow, but just for clarity we're just going to remove them in the slides.
Fade
Fading in jQuery is pretty easy. There's actually a fadeOut method that you could call. Here, when the button is clicked, we're grabbing an instance of the block element, and then calling the fadeOut method, and jQuery does the rest. In the non-jQuery version, we'll use a CSS transition to change the opacity of the element when the button is clicked. Here we grab an instance of the block element and then toggle add or remove the fade-block class. The fade-block class has an opacity of 0, which is invisible. And since we told the block that we wanted to transition on opacity, it will animate over .4 seconds in a linear fashion. If we take off the fade-block class, then the animation will go in reverse direction from invisible to visible over .4 seconds. It's important to know that IE9 does not support CSS transitions. Near the end of this module, we'll talk about what you could possibly do about that, but for now let's just talk about IE10 and the other modern browsers. So here's a quick example of the fade. We're using JSFiddle here just to play around, and we're using the Prefixfree library, which will automatically find all the properties and add the vendor prefixes. Now I don't really recommend that in production, but when you're just playing around in JSFiddle, then it's pretty good to use. And we are using jQuery for this example. So here we have two divs, a jquery-block and a css3-block, and then we have a Fade Out button. We're going to use jQuery to grab the button and add a click event handler, and then we're going to grab the jquery-block and just say fadeToggle. And then our non-jQuery code, we're going to use querySelector, grab our button, add a click event handler, here we'll grab an instance of the css3-block, and then we'll toggle this class called fade-block. If we look over here, here is our class fade-block, it has an opacity of 0. And on the css3-block, we actually told it to transition on opacity. So when it sees opacity change, we want to animate over .4 seconds in a linear fashion. So when we add this class with opacity 0, it'll say oh, I need to animate from full opacity to no opacity. And then when I take it off, it says oh, I need to go from no opacity to full opacity. And jQuery just handles it all for you, it figures that out under the covers, but it doesn't do it with CSS. The CSS technique is usually always faster because it could be hardware accelerated on your computer with a GPU, whereas jQuery just does it with JavaScript and manually changes things. It's really good for backwards compatibility, but it's not as fast. But we won't probably see the difference visually, but we're going to click Fade Out and they both faded out. And we'll say Fade In. So there you go.
Slide
Sliding elements in jQuery is also very easy to do because there are slideUp, slideDown, and slideToggle methods. What we're going to do here is when the user clicks the button, we're going to grab the block with jQuery, and then call the slideToggle method, which will slide it up on the first click and slide it back down on the second. Here, we're using a CSS transition again to help us with the sliding animation. This time we're telling the transition that we want to animate based on the height over a .4 second duration in a linear fashion. When the user clicks the button, we toggle, add or remove the slide-block class, which divides a height of 0, kicking off the animation and making it slide away. When we click the button again a second time, it removes the class, which makes the height go back to its original value, which kicks off an animation and slides it back down. Here we have another example in JSFiddle. We have a block up here with jquery and css3, and we have a button that says slide. With our jQuery version we'll grab the button, we'll grab the jquery-block, and just say slideToggle, and that'll kick off whether it needs to slide it away or slide it back. And then with the native code, we're going to select the button addEventListener, and then we'll select the css3-block and then just toggle the slide-block class. And over here, our css3-block, we define a transition that we want to listen for the height. So if that changes, we want to kick off animation over .4 seconds in a linear fashion. And here we're adding a class of slide-block, which sets the height to 0, which kicks off our transition, since it's based on height, over a .4 second duration, and it'll slide away. And then when we remove slide-block, then the height goes back to the original value and it transitions back to the original value. So if we click the button here, we'll notice both of them slide away, and then they both slide back. Very nice.
Scale
Scaling is a little bit trickier when it comes to the standard jQuery animations. There is no scale method, but we can kick in to the low level animate method and define our own custom animation. Here we tell animate that we want the left position to be cut in half, as well as the top position, and the height and width should animate to 0. The effect we're looking for is a box that's shrinking smaller and smaller until it goes away. If you were to use jQuery UI instead, then it's actually pretty easy. There's a toggle method that you could pass the string scale to and jQuery UI will do the rest. Of course, jQuery UI is yet another library, which depends on jQuery. So if scaling is all that you needed, then this might not be the best option, but it's easy to do if you have it. If you want to go jQuery-free, then you could use a CSS transition again, as we've done in the last two examples. And this time we'll use a CSS transform to scale the x and y axis to 0. When the user clicks the button, we'll add the scale-out class, which will animate the element down to 0. And if we click the button again, the class will be removed and it will animate back into existence. Another way we could have done this animation is to use the animation property and define some key frames. We define our key frame animations from the start, 0%, to the end, 100%. At the start, we want our shape fully scaled, and when we finish we want it scaled down to 0. Now that we created our key frames, let's use them. So all we have to do is in our scale-out class, we tell the animation property that we want to use our previously defined scale-out key frames over .6 seconds with a ease algorithm and to apply its final state forward after the animation has ended. So here we have another JSFiddle comparing the four different scaling techniques, jQuery, jQuery UI, CSS Transform, and CSS Animation. So the first one is jQuery, and we changed it so there's not a button, we'll just click on any of these and it'll kick off the animation. So here we're grabbing an instance of the box and then we're calling the animate method. What you do is you tell the animate method the position of where you want to be, and so we're saying we eventually want our left to be the half of the width, and we want our top to be the half of the height. And we eventually want our width to be 0 and our height to be 0 because we want the box to kind of scale out. The jQuery UI version is really easy, you just call toggle and you pass in the string scale, and it does the rest. Using our transform, all we're doing is really adding a class, scale-out-t. If we look over here, our transform, we're saying we want to do a transition on any property that changes, and we want to animate over a .6 seconds in an easing algorithm. And our scale-out-t, we say hey, we want to transform and we want to scale to 0. So that's pretty easy. And the animation looks a little bit different, but all we're doing is we're adding a class just like the previous one, scale-out-a. So here we define our key frames, at 0% we want fully scaled, and at 100% we want to scale down to 0. And then our actual class, scale-out-a we say hey, we want to use the animation and we want to use the scale-out key frames that we just defined and do it over .6 seconds in an easing way, we want it normal, and we want whatever state it's at the end, we want that applied to the element. So if we come down here and click on them, we get some pretty smooth animations, smooth transforms, some decent jQuery UI, and then the jQuery, it looked not as good. The bottom two techniques with CSS will be hardware accelerated with a GPU, and the other versions, jQuery and jQuery UI, animate only using JavaScript. So they might be a little bit slower, but they'll run on browsers that don't support CSS transitions or animations.
Easing
You might have noticed that I've used linear and ease in some of the previous examples. Well these are examples of easing algorithms, which are basically mathematical expressions which explain the progression of an animation, like if they start off slow and then get fast near the end, or if they're fast and then slow down and they're fast again, and things like that. There are several easing algorithms built in, but then again you could create your own custom ones as well. The website easings.net lets you visually see what the algorithms look like and you can see how to support them both with jQuery and with CSS. In this example, we're going to animate the left position of our box from its current position to 300 pixels. The animation will take place over 600 milliseconds and will use the easeInOutQuad easing algorithm. JQuery UI comes with lots of these easing algorithms built in that we could take advantage of. From the easings.net website, the easeInOutQuad page will show you how to support this type of easing just using CSS. It shows using the cubic-bezier function with values .455, .03, .515, and .955. In addition, there's another website called http://cubic-bezier.com where you could drag around four different points and define your own custom animation timing. So, we could use the information from easings.net and use it in our CSS transition. Here, we tell our transition that we want to use the cubic-bezier of .455, .03, .515, and .955, which will be the equivalent to the easeInOutQuad like our previous jQuery animation example. We'll tell it to animate the left property and do it over 600 milliseconds, then when we add the move class, the animation will begin just like our previous example. Now we could have instead used animation key frames, but in our case it seemed like a little overkill since our 0% frame doesn't really have anything defined, but the same idea applies. The main thing to notice here is that we're providing the cubic-bezier function with the values from our previous slide, and we're adding the move class to kick off the animation. So here's another JSFiddle with our easing algorithm. We're using the jQuery version on top and when we say animate, we'll actually provide the easing algorithm at the end, easeInOutQuad, and then we have our css3- transition and animation. And the main thing to notice since we've already talked about how to do animation, is that we're providing the cubic-bezier function with the custom animation that mimics what easeInOutQuad would look like. So when we click on them, they go fast and they kind of slow down near the end, which is really kind of nice. And so these are hardware accelerated and on your machine using the GPU, and this is just the standard jQuery version, and if we run it, we'll actually see it's leaving a trail, which is not optimal, but it is using the special easeInOutQuad algorithm.
Shim
As I mentioned before, IE9 does not support transitions or animations, so most of what we showed here would not work. So what do we do then? Well, one option is to not use CSS animations at all, but that would be unfortunate. CSS animations are super-fast because they can be hardware accelerated by the GPU, whereas jQuery animations are done in jQuery and aren't as performant. Another frame of thought is if the browser doesn't support CSS animations, that we just let those browsers not get animation. That could be okay for your application or not. It really depends if those animations are crucial to the app or not. Another approach is to have a jQuery fallback if the browser doesn't have native CSS animations. This is a little bit trickier, but it's doable, or you could possibly use a plugin like jQuery Transit or jQuery-Animate-Enhanced. You could use something like jQuery Transit, which will use CSS animations, if they're supported, integrate gracefully for older browsers. You could also write a small snippet of code to conditionally check for transition support and then reassign transition to the jQuery animate method if you need to. Or you could use jQuery-Animate-Enhanced, which will convert jQuery animate methods to use CSS transitions if they're supported in WebKit, Firefox, and Opera. Of course both this approach and the last one require that you pull in jQuery, so that may not be what you want. However, you could possibly load in jQuery dynamically when you need it, but that would complicate your code flow just a bit. In the end, it's really up to you and how important animation is to your application.
Demo
Okay, here we have our sample application again, it's a simple RSS reader for the Tech.Pro Blog. The articles are listed on the left, if we click on one, then the details are on the right. And we could click one of these filter items on top to only show the items that match, so we're going to only show the JavaScript items. And you notice it did a little animation where it faded it in and out. So what we're going to do is the last refactor to take out all the jQuery is to add in some animation. So let's go over here and we'll go and look for our TODO. And here we go, we're going to delete that. And what we're going to do is we've kind of waited for a while to refactor this just because we haven't talked about the animation, but the first thing we're going to do is not use jQuery to remove class. We could actually use classList for that, and we've talked about that before, and we could just say remove, and we'll remove that class. And before we continue, let's just do the same thing with this next one. We'll say classList and we'll say add, and that will add that class. So, for our animation what we're going to do is actually we don't need to do this at all, we don't need to call fade in because obviously we're going to take jQuery out. But if you remember, for a lot of the animations that we've done before, we've kind of just kicked off the animations just by adding or removing a class. So that's what we're going to do here. We are going to have a fallback, so we're going to look to see if our browser has transition inside of one of the elements, we'll just pick body.style, for example. And then what we want to do is say if it doesn't have that, so for example if this happens to be IE9, then let's do something else. And what we want to do is after we animate opacity to 0, it's still going to contain some space, and we want it actually to go away because we don't want to see all that empty space. So what we're going to do as a fallback is just to add a class of byebye, and that makes it essentially go away. But if we think about it, we need to do the same thing for modern browsers too. So what we could do is wire into an event that happens when an animation ends, and then we'll add the byebye class as well. So let's go in here and add a new method called setTransitionEnd. And what we'll do in here, and we'll call this up above, but for now let's just write it. What we're going to do here is just define some nodes and we're going to call this when the items have been displayed for the very first time. So we're going to do querySelectorAll and we'll look for all the list- group-items, and then we want to loop over them, so we'll do a forEach and we'll do call since it's a node list. And we'll pass in our nodes and here's our function that we want to invoke for each item. We'll pass the node. And here for each node we want to add an EventListener so when the transition has ended on that particular element, so after the animation is complete, so we'll take that node and what we want to do is we want to actually add the class of byebye because after the animation is complete, it will be gone, we can't see it, but we actually want to remove it from the DOM, or at least make it look like it's gone. So we need to somehow call this method. So let's go up here to the top and listen to postsDisplayed. And when that happens, not only do we want to set the default for the first time, but we want to call setTransitionEnd. And this message is actually only published one time. The very first time, it got all the information and displayed it in the DOM. From then on, the filter either hides or shows them. So now we got all the JavaScript wired up, so let's go over to our CSS and see what we need changed there. So we'll need to define a couple things, one first let's define our list-group-item. And there's a couple of things on here we need to add. This is where we're going to define the transition, so we want to transition on opacity for 400 milliseconds in a linear fashion. And what we'll need to do is to support older browsers, we'll just make several versions of this and we'll add webkit here and we'll add moz here for Mozilla and then we'll add Microsoft and we'll add Opera. And actually, Microsoft doesn't have a vendor prefix, so we'll just take that off for now. And then what we'll do is we'll define our fade-out. So our fade-out byebye, that's the one we want the element to be completely gone. Now it would be nice if we could say display none here, but that doesn't work unfortunately with animations. So what we're going to do is we're going to set the position to absolute and we'll set its left to something really far off the screen, which seems a little silly, but it's kind of what you need to do if you want this to work well with animations. And so if we have a list-group-item that has fade-out on it, then what we're going to do here is we're going to say we want to change the opacity to 0. So anytime we add the fade-out class, opacity 0 is changed, which kicks off our transition and says oh, I'm listening for changes in the opacity, let's animate over 400 milliseconds. And then our JavaScript will kick in, we'll listen for the transition end, we'll add the byebye, which basically kicks it off the screen and makes it absolute, which it removes its location. So, now let's go over to our index page and we need to actually remove jQuery. So that's good and let's go back over to our code and we'll remove all instance of jQuery. So this one here we don't need and then up here we don't need that one, and then we don't need to pass it in anymore. So now if we search for jQuery, it's nowhere to be found. If we search for the dollar sign, it's nowhere to be found. We'll save, come back to our code, we'll refresh, and there we go. Here's our new application with no jQuery. We could click around, change the articles. We could click JavaScript and it will just show us the items with JavaScript and we could take it off and it will animate slowly, and we're good.
Native Plugins
Introduction
Hello, this is Elijah Manor, and in this module we're going to talk about plugins. We'll first discuss about plugins that maybe shouldn't be jQuery plugins, and talk about how to think about making plugins that are native JavaScript. And then we'll show how we could create an adaptor so that it could also work as a jQuery plugin. Plugins are great, and jQuery gives us a great starting place and has enabled developers to fill in the gaps and get really creative about what they want. Plugins are similar to components you might find on your computer. You could swap them out or find a better one, or even come up with something that's new and forward thinking. As long as your plugin follows a certain API, then jQuery developers should know how to use it. Plugins are one of the many reasons that jQuery has become so popular. Since they're easy to create, a lot of developers started making plugins and the community around it grew very quickly. There are a huge number of plugins in the jQuery ecosystem, ranging from both very simple to very complex. However, one of the downsides is that the quality of these plugins is hard to gauge, but you tend to get that when something's really popular. Anyway, one of the interesting things about some jQuery plugins is that some of them don't need to be jQuery plugins, meaning they don't really even use jQuery inside of them, or they could have been easily written so that they didn't need jQuery. So we're going to talk about some of these concerns and how to work around them.
jQuery Plugin as A Namespace
One technique that you might run across is using the jQuery object as a namespace only. For example, this logger method is placed on the jQuery object. Does it use jQuery at all? No. Is it even technically a plugin? No. Why not? Well jQuery plugins define themselves off $.fn, jQuery's prototype so that it could be used after you've selected elements from the DOM. But this library has just attached itself to the jQuery object as a convenient location. There's no real reason or functional benefit to do this. Yes, having a namespace is important to keep down on global variables, but using jQuery's object isn't necessary. My guess is the main reason why this technique is used is because people are familiar with jQuery and since jQuery is very popular, if you attached yourself to jQuery, then it might be more popular as well, or at least more familiar to use. If you did want to define your library off the jQuery namespace, then maybe consider doing something like this, where if jQuery is present, you attach yourself to it. Otherwise, if jQuery is not present, then you create your own namespace and place your functionality underneath it. This is a good compromise because it could keep people familiar with how to use it off of jQuery, of if they don't have jQuery, they could still access it somewhere else. The code will assign jQuery to the local dollar sign, if it's available, otherwise it will use the existing etm namespace, or create a new etm namespace if it hasn't been created yet. That way we'll default to the jQuery namespace or use a custom one as a backup. So if jQuery is on the page, then you could use the logger off of jQuery, or if jQuery isn't on the page, then you could use etm as your namespace and call the logger method off of that. Another way to code the same thing would be like the following. We're still using an IFFE, but this time we're passing in our namespace instead of figuring that out inside. The rest of the code is pretty much the same.
Simple jQuery Plugin
So let's take a look at a really simple jQuery plugin, actually most of the code is commented out because it's not important for what we're going to talk about. This is a little tooltip plugin that will grab the title off any element you provide it, and create a tooltip when you hover over the item. We're obviously using jQuery since it's a jQuery plugin, but if you look closer, we aren't really doing a whole bunch that really needs jQuery. We are adding event handlers, manipulating the styles, changing the text, and things like that, but we can do all those things pretty easily without jQuery, right? Imagine how many other people could use this plugin if it didn't depend on jQuery. Maybe a Dojo person wanted to use this or a Mood tools developer. Or what if someone who didn't want to use any of these libraries at all wanted to use it, wouldn't it be nice to have a bare bones version? Well, that's what we're going to look at doing.
Convert: Extend
So first let's tackle the extend piece. This utility method is used to merge custom settings onto the default settings. As you heard me mention about this is in a previous module, the code to do this is not trivial and it isn't native. So what we could do is just take each option separately and check their values and default them if needed. It ends up only being several lines of code, so I'm good with that. If you really wanted a slick method, you could also bring in underscore or low dash and use its extend method, but you probably don't want to rely on a whole other library just for the small feature when our previous snippet should do just fine.
Convert: Create
The next main piece that needs to be changed is the creation of the tooltip that will be used and shared throughout the plugin. jQuery makes it really easy to build DOM elements, you just wire up some markup and jQuery does the rest. To natively create these elements, we're going to use the createElement method, set its ID and innerText properties, and then append the element to the body. You might be wondering where the code is to set the CSS styles. Well we actually did that in the previous slide when we were manually setting the options and defaults.
Convert: Event
Next we need to convert the event handlers, which end up being pretty easy. Instead of using the two parameter version of the jQuery on method, we'll just use the addEventListener method off our element. That's pretty straightforward, which is nice.
Convert: Position
Now we need to convert the piece of code updating the text and position of our tooltip. Changing the text isn't a big deal, we could just use the innerText element property for that. However, updating the position is a little trickier. Thankfully it didn't end up too bad. For the tooltip's new top, we're able to take the element's offsetTop and subtract the tooltip's offsetHeight. And for the tooltip's new left, we'll just that to the elements offsetLeft. And then we're done.
Simple Library
So our new non-jQuery plugin looks something like this. It's now just a JavaScript Tooltip library. The way we use it is grab some elements, initialize the library, and call the wire methods for each element that we want to use the tooltip on. However, we may have just alienated all the jQuery levers out there. It's just so easy to use a jQuery plugin, someone might still want the ease of that use. So what do we do?
jQuery Plugin Wrapper
So, we can make a jQuery plugin around our Tooltip library. We'll essentially create an adaptor to our JavaScript library. Here we initialize the library, iterate over the jQuery's collection, and initialize each element, and then return the result of the each, which allows the plugin to be chainable, and we're done. Now we have a generic tooltip JavaScript library for whoever wants to use it, and also a jQuery plugin for those who want to use that. Yay! I'd probably have two scripts to download, one with just the JavaScript library, and another one with both the JavaScript library and the jQuery plugin wrapper around it. That way someone who likes the jQuery way will only have one file to download. And with that, we have a happy developer who either uses jQuery or doesn't use jQuery.
Demo
Alright, here is a web page that will use a jQuery tooltip. If we'll come over here and run our tooltip, we'll see that when we hover over it, we'll actually get the message, and when we come into our code, we'll see that the anchors have a title and we're just pulling off the title and using that as a the tooltip message. Initially we're just going to use the tooltip jQuery plugin, which is jquery.tooltip.js, so we'll take a look at that. And here again we're defining the jQuery plugin off jQuery fn and we're using extend and we're doing a loop here and returning so we could actually have chaining. Inside here we're creating a new tooltip if it doesn't exist and adding our CSS options, adding a couple event listeners, mouseenter and mouseleave. The mouseenter figures out where the tooltip should go and changes its text, and on leave we throw it off the screen so we don't see it anymore, and here are our default colors. So we could take that code and come over here and just make a general library. So here reason IFFE and we're going to pass in a namespace of tooltip. And we'll still have an init, and what it will do is it'll see if the element exists or not. If it doesn't, it'll actually create it, give it an ID and text, and append it to the DOM. Kind of like what we were doing before. And then instead of using extend since that's kind of complicated code and we're not going to use jQuery or underscore or low dash, we'll just manually create our options and check our defaults in a couple lines of code. It's not too hard. We'll see if they passed in something, if they didn't, we'll use the default. And when we wire up, we could just say addEventListener, mouseenter, mouseleave, we'll set our text with innerText. And to set our top and left we'll just do a little bit of math, we'll take our element.offsetTop and subtract our tooltip's offsetHeight. And for the tooltips left, we'll use the element's offsetLeft. And then with the mouseleave, we'll just kick it off the screen again and pretty much that's all there is. If we come back over here, what we'll do is comment out the jQuery plugin and then we'll uncomment the code to actually use our library. Now it's a little more complicated, it's not jQuery ish. We're going to grab all the anchors, initialize our library, and loop over and wire up each of our elements. It will work though if we save it and come back over. We'll see it's being applied. We're using slightly different colors, but that's okay. But let's go one step further, let's take our library, which is good, because now pretty much anyone can use it, and let's create a wrapper around it. And what we're going to do is call it jstip, and now it's really small. It's still a jQuery plugin, we're putting it off of jQuery's prototype, but now we're just initializing our Tooltip library, we're doing a jQuery each, and returning that so it's chainable. And inside each one we're just calling the wire method to set everything up. And that's all there is to it. Now if we come back over here, we can make sure we didn't break anything, and sure enough, the things still work just fine. Now if you're going to create this adaptor, it'd be great if we could just have one file that has the library on top, and then have this adaptor at the bottom. Either do that in your file our use some build system to do it, but that way if you really are targeting to a jQuery developer, then they have all they need in one file instead of having to download two and figure out the right order and all that stuff. And then you'll have your other script, which is just a library by itself, and that could be used by whoever you want. So hopefully you can see the value of separating these out. And you could go one step more, you could make adaptors for other libraries. It doesn't have to be jQuery, but that's just an example.
Summary
So, in summary, some jQuery plugins probably shouldn't be jQuery plugins in the first place. And some jQuery plugins aren't plugins at all, they just use jQuery as their namespace. In that case, it'd be nice if jQuery wasn't included on the page, if another namespace could be used instead. Also, it might be good to remove jQuery as a dependency to your plugin if at all possible. That opens up the use of your library to other developers as well who might not use jQuery. In addition, it'd be nice to provide a jQuery plugin adaptor around your generic non-jQuery library, to make it easier for those who do use jQuery to adopt it into their project. This technique can benefit a larger crowd, and you could even make adaptors for other frameworks as well if you wanted.
Course author
Elijah Manor
Elijah Manor is a Christian and a family man. He is a Microsoft Regional Director, Microsoft ASP.NET MVP, ASPInsider, and IE userAgent and specializes in front-end web development. He enjoys...
Course info
LevelIntermediate
Rating
(190)
My rating
Duration2h 26m
Released30 Oct 2013
Share course