Practical and Effective JavaScript

Practical and Effective JavaScript

with Joe Marini

 


JavaScript is essential in the creation of powerful web sites and applications. In Practical and Effective JavaScript, instructor Joe Marini presents the next level of features that experienced developers need to streamline their workflows and introduce dynamic new functions to their projects. Joe teaches tips for improving JavaScript performance, ways to separate programming behavior from page content, and principles for understanding the modern DOM event model. Finally, Joe introduces some of the more advanced concepts recently built into JavaScript. An understanding of the JavaScript language is a prerequisite for this course, which includes exercise files.
Topics include:
  • Using built-in language features
  • Creating reusable modules to save programming time
  • Dealing with dynamic and complex events
  • Understanding object-oriented JavaScript
  • Reviewing practical JavaScript examples to use in the workplace
  • Discovering tools for debugging and developing websites

show more

author
Joe Marini
subject
Developer, Web, Programming Languages, Web Development
software
JavaScript
level
Intermediate
duration
5h 37m
released
Apr 21, 2009

Share this course

Ready to join? subscribe


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:00(Music playing.)
00:03JavaScript has grown from a simple language for adding interactivity to
00:07web pages to a full-featured programming language. If you are building web
00:10applications, you need to have knowledge of this language on your belt more
00:14than ever before. I'm Joe Marini. This is Practical and Effective JavaScript.
00:19I have spent a better part of my career working in the web and graphics
00:22industries as a developer, instructor and author. This title is aimed at
00:26familiarizing web designers with some of the more advanced concepts recently
00:30introduced into JavaScript.
00:31We'll take a look at the modern DOM Event Model, get in to the features of
00:35object oriented programming and I'll show you how to separate programming
00:39behavior from the page content. I'll also give you some tips on how you can use
00:43progressive enhancement in your web pages, show you some great tools for
00:47developing and debugging your scripts and provide a set of finished examples
00:52that you can then reuse in your web pages.
00:55Every topic I cover in this course will help prepare you for working on more
00:58advanced websites to have increasingly demanding features. So let's learn
01:03the language of the web with practical and effective JavaScript.
Collapse this transcript
Using the exercise files
00:00If you are a premium member of the lynda.com Online Training Library, or if
00:04you are watching this tutorial on a disk, you have access to the Exercise Files
00:08used throughout this title. The way the Exercise Files are laid out are
00:12according to each chapter as I go through the entire course. So you can see
00:16here in the exercise_files folder I have got chapters 2, 3, 4, 5, 6 and 7, each
00:21of those has example files.
00:24Let's take a look at chapter 5, for example. You can see that I have provided
00:27starting points and finished points for each lesson. If you want to follow
00:31along with me during the movie, you can open up the starting point for each one
00:35of the files on your own computer and follow along with me as I do the work or
00:39you can just open up the finished file and jump right to the code to see how it works.
00:42Chapter 7 is a bit of a special case. In this chapter I have actually provided
00:46a whole bunch of real life finished examples that you can use in your own
00:49sites. So if you have accessed these files, please feel free to take the code
00:53that you see in here, drop them into your own sites and make yourself a lot
00:56more productive.
00:56Now if you are a monthly or annual subscriber to Lynda.com, you don't have
01:00access to the Exercise Files, but you can follow along with me by watching the
01:03movies as I go through them. I have provided access to most of the code in each
01:07one of the files. So you can pause the movie along the way to type along with me
01:11and enter the code yourself into your favorite editor. All right, let's get started.
Collapse this transcript
Using the right tools
00:00Before we get started working with JavaScript, I wanted to point out to you
00:03that there is a wealth of tools available for developers who want to work with
00:07JavaScript code, both for the Windows and Macintosh platforms.
00:11It doesn't matter which one you are on.
00:13The tool that I'm going to be using throughout this title is called Visual Web
00:17Developer and it's a free tool from Microsoft and that's this guy right here.
00:21So let me just quickly jump over to that tool and show you what it looks like.
00:25Okay, this is Visual Web Developer. Again, like I said it's free and I provided
00:29the URL for you to download this if you happen to be running on Windows.
00:33You can use this tool, it has a built in JavaScript debugger, it's got a great
00:36editor and that's why I'm choosing to use this. But there are other great
00:39tools. So let me switch back over to the slide.
00:43So again, if you're working on Windows, you can use Notepad. That actually
00:46comes with Windows, it's built-in, or you can use a professional editing tool
00:50that you might already have such as Expression Web or Adobe Dreamweaver.
00:54Similarly, if you are working on the Macintosh, there are some really great
00:57Shareware and Freeware products available. BBEdit is one of my personal
01:01favorites. It's a great editor. TextMate is also really good as well as Web
01:04Scriptor, and again, I provided the URLs for you to investigate all of these.
01:08Of course, Adobe Dreamweaver works cross-platform, so you can look at that
01:12product as well.
01:13Okay, so now that we know what tools we have available at our disposal,
01:15let's go ahead and get started.
Collapse this transcript
1. Writing Better JavaScript Code
Writing better code
00:00Perhaps,= a great place to begin is looking at the need for effective JavaScript
00:04practices and why we should be worrying about this. JavaScript has evolved and
00:08grown a lot from its early roots as a simple language for adding interactivity
00:13to web pages. What we have today is a fully featured object oriented
00:18programming language that lets you do a lot more complex things than JavaScript
00:23used to be used for.
00:25Types of scripts that people write today have changed dramatically over time.
00:29If you think back to what JavaScript was originally used for, it was mostly for
00:32things like rollover images and form validation.
00:35If you look at the kinds of scripts that are being written today, you have got
00:38a whole lot of complex interactivity going on, there is this whole two-way
00:43server interaction with AJAX now that's all the rage. You have got full access
00:48to the page content because the browsers implement the Document Object Model or
00:52the DOM now.
00:53So the types of scripts have really grown over time to become a lot more
00:57complex and this has given rise to the need for a lot better effective
01:02JavaScript writing ability. JavaScript itself has also changed to add new
01:06features that enable better programming.
01:09Things like exceptions and regular expressions, these are things we'll be
01:13covering later in the course, but I'll just give you a quick taste of what's to
01:16come. Exceptions, for example, are a way of handling errors and conditions that
01:21go bump in your script a lot more efficiently and professionally than just
01:26doing clean old error detection.
01:29Regular expressions are a way of dealing with texts and patterns that recur
01:32throughout content in your web pages and your scripts. Namespaces and modules
01:36will show you how to build reusable models of code that you can use across your
01:40websites and maybe even give to other people.
01:42Object oriented programming is a way of creating code that evolves over time in
01:48an extensible fashion and can be reused in multiple different sites and
01:52projects. All of these promote better methods of writing and maintaining code.
01:58Okay, let's take a look at some ways to write better JavaScript code. First,
02:02always declare your variables before you use them. Undeclared variables are
02:06global, by default, and this can cause some pretty bad side effects.
02:10You can imagine if you have got a function and you are using a variable in it
02:14that you haven't declared and you are using the same variable name in another
02:17function elsewhere in your script and the two functions are being called either
02:21by each other or somewhere else. That's going to have pretty bad side effects
02:25pretty quickly.
02:26These kinds of errors are really hard to track down. So always declare
02:31variables before you use them and, in fact, try to stay away from global
02:34variables because they are just not a good practice. This one may seem a little
02:38bit silly but you should always use semicolons to terminate your JavaScript statements.
02:43Now JavaScript does not enforce this rule, you can terminate your statements
02:46with just a carriage return, but using semicolons is a nice explicit way of
02:52saying here is where this statement is. It's always a great practice when you
02:57are writing code to rely on explicit behavior rather than implicit things. So
03:04simply, that seems it makes the code a lot easier to read.
03:06Always use semicolons.
03:07Okay, I have said this before, I want to say it again, avoid using global
03:11variables. You should use something called a namespace instead, which we'll
03:14cover later in the course. This will help prevent collisions with other script
03:19libraries or even your own script from using the same global variable twice in
03:24a context that you hadn't thought of. So avoid using global variables,
03:28we'll show you a good way of doing this later on in this course.
03:31You might consider using something called a coding notation method, such as
03:35Hungarian Notation. That's one of my personal favorites. This is a way of
03:39writing your code in such a way that just by looking at the code, you can see
03:42what's going on and you can spot bugs before they happen and we'll cover that in a moment.
03:47Finally, avoid using constructs in the language that make code just plain old
03:51hard to read or maintain and a good example of this is the Eval statement.
03:55The Eval statement is, besides not being particularly secure, it just makes code
04:00harder to read and harder to go back and fix because it's not really part of
04:05the code you have written that gets interpreted at the time when the page gets
04:10loaded. It gets evaluated later on in the process and it makes debugging really
04:13hard. So avoid the Eval statement and other things like it that make your code
04:18harder to maintain and read.
04:19I mentioned Hungarian Notation in the previous slide and this is a method of
04:24naming elements of your code. It was introduced by a man named Charles Simonyi
04:28who worked at Microsoft. It's really just a way of naming things in your code
04:32to make potential bugs easier to spot before they happen and just make your
04:37code more understandable, not just for other people but for yourself.
04:41If you come back a couple of years later and you are looking at some code and
04:44you are not really clear on what things are happening and why, this is one way
04:47to help make that easier to understand. So you can see I have got a couple of
04:52examples in the table here. Essentially, what I'm doing is I'm naming variables
04:56and functions according to what kinds of content those functions or variables work with.
05:02So in the first row there, you can see I have got a Boolean value and it's
05:05called bIsRegistered. Now if I just deem that variable is registered, I might
05:10be able to go down a line that it's either true or false. But by explicitly
05:14putting the B in front of it, I can say oh, that's a Boolean. It's going to be
05:17either true or false. If I'm debugging later on and the content of
05:22bIsRegistered is a string, I know that something is probably gone wrong somewhere.
05:26Similarly, you can name variables with prefixes that indicate what they do in
05:31addition to what kinds of content they hold. So the next couple of examples are
05:35good for that. You can see I have got variables named cElements and nTags in
05:40the second line. That indicates that these variables are used to hold a count
05:44of some number of items.
05:46In the next line I have got an array. What I have done is I have named it
05:50aNames or in the second example asNames. What I'm doing is I'm combining a
05:55couple of prefixes here. So S for String and a means array or you can call
06:00something like arr, and you know, I don't know. Maybe you've got lot of pirated
06:04content in your scripts or something, but that's not what I use it for, I use
06:07it to indicate that the content is an array.
06:10You can look down a little bit further. I have got things like indexes. You can
06:13see that I have named a variable iName, which is indexing into the aNames
06:18array. Then finally, at the bottom row, you can see I have got a couple of
06:21prefixes that indicate whether a variable is global or a member of an object
06:27and we'll cover that a little bit later in the course. But I know I said
06:30earlier, don't use global variables, but if you have got a global object to
06:33that you are using as part of a namespace, you can prefix it with the g_ to
06:37indicate that it's used globally.
06:39Perhaps, it's best to look at an example to see how some of these practices
06:44make code easy to read. So let's take a look at an example of code to see how
06:50it looks when we haven't followed these practices and you can see them in the
06:52left here. Don't worry about what the function does. I'm just using it as an
06:56example to illustrate some of the concepts we just talked about.
06:59So you can see here I have gotten a semicolon. I haven't declared any
07:02variables. There is no comments. It's really kind of just plain text on a page.
07:07It's kind of hard to read. Let's look at the same function however on the right
07:10hand side when I have declared my variables, I have included some comments,
07:16I have prefixed my variables with things like G for Global and B and I for
07:22Booleans and Indexes and I have put semicolons in the statement.
07:26Now, I don't know about you but maybe even though the right hand side is a
07:30little bit more verbose, it's just easier to read. I have got some comments in
07:34there that explain what's going on, I have declared my variable, so I don't
07:38have to worry about name collisions later. I have got some prefixes that
07:41indicate oh, okay, well the ascending variable means that it's a Boolean that
07:47tells me whether I'm sorting something in ascending or descending order.
07:51I have got the giCol variable that's an index into the column of a table that's
07:56being sorted. It's just a lot easier to read. So this is a good example of why
08:01you'd want to follow these kinds of coding conventions just to help you read
08:05and maintain code down the line. Okay, so that's pretty much how we write
08:10better JavaScript code.
08:11Next, we'll take a look at some of the built-in JavaScript language features
08:15and how we can use those.
Collapse this transcript
Using built-in language features
00:00The JavaScript programming language provides several built-in language features
00:03to help you write more effective JavaScript code, so let's take a look at those.
00:07First, you should use built-in functions on libraries whenever possible.
00:12JavaScript provides several built-in classes and libraries like the math and
00:16date libraries and libraries for working with strings and regular expressions.
00:20We'll cover some of these later.
00:22The reason you want to use these is because it's code that the JavaScript
00:26interpreter and browser have provided for you, so you don't have to write it.
00:30These methods are implemented in native code in the browser, and what I mean by
00:34native code is typically these browsers are not written themselves in
00:39JavaScript; they are written using a language like C++ or Java or .Net, and
00:43those languages are much more efficient because they are called
00:45compiled languages as supposed to JavaScript which is an interpreted language.
00:49So just by using the code that's already built into the browser you are going
00:53to get better performance and it's code that you don't have to write and
00:56maintain yourself.
00:57So you see the example I provided down there on the bottom of the slide.
01:01This code basically checks to see if a string contains only alphanumeric characters.
01:07Now if you wanted to write this yourself you would have to write a loop that
01:11looped over every single character in the string and tested to see if it was in
01:15the range of lowercase or uppercase letters or digits. In this case I'm using
01:19something called a regular expression. Now don't be afraid if the code is
01:23written there because we'll cover this later on in the course.
01:25But essentially what I have done is I have collapsed a function that I would
01:28have had to write to myself into two lines of code. This is a much better way
01:33of taking advantage of the built-in JavaScript capabilities than having to
01:38write them myself and then go back and maintain them over time.
01:41Another great feature of the JavaScript language is anonymous functions and
01:45anonymous functions are functions that are passed as arguments to other
01:49functions or declared inline and have no name.
01:53Essentially they allow you to skip a step and just declare and assign them like
01:57you would any other variable like a string or an object or something. So let's
02:02take a look at an example here. In this example I'm assigning the Windows
02:07onload event to a function, and you can see I'm just declaring the function
02:11right inline there with the word function and some empty parenthesis because it
02:14doesn't take any arguments and it just shows an alert. That says hey,
02:18the window loaded.
02:19This is different than writing window.onload= and then the name of some function
02:24and then declaring the function elsewhere in the script. Anonymous
02:28functions are a much more efficient way of writing functions in some cases and
02:32we'll be using this example throughout the course. So I want to introduce this
02:37to you here to get you used to the concept.
02:38A good example of using anonymous functions comes when you are using the Sort
02:43function on the array object. Now the Sort function, again, it's an example of
02:48piece of code that's been written for you by the JavaScript interpreter and
02:51it's in the browser so you don't have to write it yourself. Works one of two ways.
02:55You can call it with no parameters and when you call with no parameters
03:00the elements will be sorted alphabetically ascending and they are converted
03:05into strings if possible. So if you had an array of objects they would first be
03:10converted into strings and then sorted.
03:11Or you can call your Sort function with another function as an argument, and
03:18when you do that the JavaScript interpreter will then call that function and
03:23essentially ask it, hey, which one of these two things comes before the other?
03:27This is an example of what's called the call back function and it's called the
03:31callback function because JavaScript is calling back into a function that
03:34you have provided. So to see how this works take a look at the example I have got here.
03:39Suppose I had an array of strings and you can see I have got a variable
03:43there, masters, and it's an array of strings 1, 2, 3, 4, 5 and 6.
03:48Now suppose I wanted to sort this array not by alphabetic rules but by how long
03:52each string is. The way I would do that is I would call the Sort function,
03:56you can see that on the second line, and I'm passing in an anonymous function that
04:01takes two arguments. First argument a, second argument is b and it's returning
04:06the result of subtracting b's length from a's length. Now the way the call back
04:11function for sorting works is if you return a value that's less than 0
04:16that means the first argument a comes before b. If you return a value that's greater
04:22than 0 that means the b comes before a, and if you return the value 0 it means
04:28that the two elements are the same and neither one comes before the other.
04:32So if we were to execute this code you can see the result come back. 1 and 2
04:37and 6 would come first because those are three characters. Then 4 and 5,
04:42because those are four characters, and then 3 because that one has five
04:46characters. So using anonymous functions is a pretty efficient way of working with JavaScript.
04:51A couple of other things I want to cover quickly, the continue statement.
04:55The continue statement you use inside loops to basically skip the rest of the body
05:00of the loop and continue with the next iteration. So you can see in the example
05:05I have on the right-hand side on the top. I have got a loop and somewhere
05:09inside my loop I test for some condition and if that condition is not being
05:13met for some reason, I have a continue statement below it that basically says
05:17hey, skip all the rest of the code that's in the loop below here and just go
05:21down to the bottom brace and then back up to the top, increment the value of i
05:25and continue on. This is just a more efficient way of skipping loop logic than
05:29writing a whole bunch of nested if and else if statements.
05:34On the bottom, if you have ever seen the for in construct before, it basically
05:39provides a way of discovering the properties of an object dynamically. Because
05:43remember in JavaScript you can add properties to an object at any given time.
05:48So suppose I had an object called Portfolio and on the portfolio I had
05:53properties, and again, we'll cover these concepts later on in object-oriented
05:57programming if you are not familiar with them but just stick with me for now.
06:00Suppose I had different stock symbols that were properties on the object.
06:04Rather than keeping track of each one of those individually in some other array,
06:08I can use the for in construct to loop over each one of those properties
06:13whatever they are and discover them at runtime.
06:16So here I have got a number that represents the total of the portfolio and for
06:20each one of the properties which would be a stock symbol, I then index into the
06:24portfolio object to extract its value and then add it to the total. This is a
06:28much more efficient and readable way of working with properties on objects and
06:33we'll see examples of it later. And finally let's take a look at some
06:37JavaScript gotcha's that you want to avoid in your scripts.
06:41First, remember that objects are associative arrays and what I mean by that is
06:46I can write object.property and that's the same thing as writing obj and then
06:50in brackets the word whatever the property is.
06:53So you can treat objects as arrays, you can treat arrays as objects; they are
06:58kind of interchangable. Remember also that these associative array keys that's
07:03what that property string is there on the upper example. Those are converted
07:07into strings before they're used as accessors. So in this example if I write Obj
07:13and then 3+4 that's going to be the same as passing a string the string 7 as
07:19the bracket example there on the right. So if you've got code and you are using
07:24associative arrays and you are not getting the results you think you are getting,
07:27this is a pretty good place to start looking. Are you trying to do
07:31math and not expecting the result to be a string?
07:34Also watch out for modification of objects inside of loops. I see this all the time.
07:38So let's take a look at an example. Suppose I have some code that has a
07:44loop going over some array. You can see here I have got my example. I have got
07:48a variable name cElems. I'm using my Hungarian notation there, and it's looping
07:52over my array. I have sent it to the value of the length of my array and in
07:55this I have the loop.
07:57I am doing something with the array and then I call the pop function. Now pop
08:01modifies the array in a couple of ways. First it takes one of the elements of
08:05the array off of the array and then it decrements the value of the array's
08:09length. But you can see I haven't updated the value of the cElems variable to
08:13reflect that. So again if you've got code and you are working with arrays and
08:18you are modifying the array contents and you are getting some weird errors,
08:21and not sure why, this is a good place to start looking.
08:24And finally let's take a look at a content known as pass by value and pass by
08:27reference. In JavaScript primitive values like simple numbers and Boolean
08:33values and such are passed into functions as a distinct copy of themselves.
08:39So if you change them inside functions that you have called with those values that
08:42has no effect. Look on the left-hand side I have got a function int f and a
08:46function named h. So in the lower function h I have got a variable named x
08:50and I'm setting it to be 5. And then I call f with x, and then inside f I'm adding 5 to
08:56the value of x.
08:57Now inside function f, x will be 10 because that's the local scope of function f,
09:03but once function f comes back, back into function h, x is going to go right
09:07back to being 5 again because I can't change the value of x and have it persist
09:12outside that function. That's because I have given f a copy of the value of x,
09:18not the actual variable itself. So when function f returns back into function h,
09:22x is still what it was before it went in there.
09:24Now objects and arrays don't work like that. Those are passed by what's called
09:28reference. If you change the contents of an object or an array inside of a function
09:34that change does in fact have an effect outside that function.
09:39So let's take the same example functions f and h, only in this case I'm working
09:43with objects. So in function h you can see I'm setting the variable x to be a
09:48new object and then on the x object I'm setting the d property to be a new date.
09:53Okay, now I call the function f with x and inside function f I set the d
09:58property of object to be a different date by calling the New Date constructor.
10:03Now when f returns and we are back inside h, the d property on the object
10:08I passed in has in fact changed. So watch out for this while you are writing
10:12JavaScript code.
10:13Okay, that brings us to the close of writing code using built-in features of
10:17JavaScript. Next we'll take a look at how you can write code that gives you
10:21better performance.
Collapse this transcript
Improving JavaScript performance
00:00Let's begin by looking at ways to find and eliminate code that is redundant and
00:04inefficient. In this example I have a loop and the loop has a variable named j
00:09and it's looping over the documents. getElementsByTagName function, it's
00:14getting array of all the a tags in the document. I have got a couple of strings.
00:18You see I have a PrefixStr call Found element. I have a variable named
00:22aElements, which is being set to results of the getElementsByTagName function.
00:27That's a DOM function that gets all of the tags in the document that you pass
00:32as the argument.
00:32If you're not familiar with any of these functions, don't worry too much about it.
00:35Right now I want you to just focus on how the code is being called rather
00:40than what functions are being called.
00:42Then finally, I have a variable here named sElemStr and I'm setting that to the
00:47result of the PrefixStr plus the tag name that came back from the particular
00:52index in the array and then calling alert.
00:55Now, this code is pretty inefficient for a number of reasons. Let's take a look
00:59at the cleaned up version to see why. So first, there is no reason to be
01:03calling document.getElementsByTagName every single time to the loop just to get
01:07the length, especially you don't need to call it again in here. That's a
01:11redundant call. I have already called it once; it's not going to change
01:14anywhere in this loop that I'm working on because I'm not changing any of the
01:18elements in the document. So I extract that out above the loop and make it a
01:23variable outside of the loop up here on the top.
01:25Also, you notice that sPrefixStr never changes inside the loop. So why am I
01:30declaring it over and over again inside the looping construct? I just moved
01:33that outside the loop as well.
01:35The next thing I do is rather than call this function
01:38document.getElementsByTagName every single time just to get the length, which
01:42doesn't change, I make a temporary variable named cElems. I set that to be the
01:48length of the aElements array, and what I'm left with is a nice tight little
01:54fast loop that-- All it does is call the same alert function that you see in
01:58the original. I'm calling that again down here, but now I have got all my
02:02variables outside the loop and the only thing I need to worry about is the
02:06looping variable that's looping over all of the different contents of the array.
02:10So we've made that thing nice and efficient, let's move on to the next example.
02:14Next example for getting better performance is don't use the with statement.
02:18The with statement is a statement provided by JavaScript to simplify writing
02:23code, but it results in slower performance.
02:27So in the top example here I'm using the with statement to say with, and then a
02:32whole bunch of properties: information, settings, files on this test object.
02:37What that basically does is it allows me to keep from writing
02:40test.information.settings.files.primary and then
02:44test.information.settings.files.secondary. I just simply say with one time,
02:49this context right here, and then I just write primary, secondary, and
02:53tertiary, all of which are properties on the files object.
02:58Now, that might look nice and efficient. It looks like it's allowing me to
03:02write less code, but the way JavaScript works is this actually results in
03:06slower performance. So to clean this up what you would do is use a temporary
03:12variable instead to dereference the objects.
03:14So I would say var temp equals and then the same string here,
03:18test.informations.settings.files, and then I would write things like
03:22temp.primary, temp.secondary, temp. tertiary. This is a lot more efficient than
03:27using the with statement.
03:28Let's move on to the next example. The next example is avoid using the eval
03:33and Function constructors. If you are not used to the Function constructor or
03:37using eval, let me just say that basically the reason why you want to avoid
03:41this is the JavaScript interpreter has to fire up a new interpreter instance to
03:46figure out the code that you pass in as strings every time you do it. So let's
03:52look at an example and this will become clear.
03:53I've got a function here called addMethodToObj and it takes an object as an
03:58argument and the property I want the function added to, and then the string
04:03that constitutes the function's code. The body of this function says okay, on
04:08the object and the property I was given, call the new Function constructor,
04:12which then interprets the code that it was given and makes a new function.
04:16So to see it in action I've got two calls here and I'm calling addMethodToObj
04:19on some object I've got declared and two methods, one called rotate90 and
04:26rotate60. This is the code that's going to be passed in as the body of the function.
04:31Now, again, don't worry too much about the actual code, it's just an example.
04:35So what's happening is every time this addMethodToObj functions gets called,
04:39the new Function constructor is being invoked and that's a very slow way to do things.
04:44The JavaScript interpreter has to interpret this code and that's not
04:48very efficient. So the way you make this more efficient is by using anonymous functions.
04:53So this is the same example. What I'm doing here is instead of assigning the
04:57Object's Property to a big string and invoking the Function constructor,
05:02I'm actually passing in the function that I want assigned to the property. So in
05:07addMethodToObj, I have got the Object and rotate90. Those haven't changed, but
05:12instead of passing in a string, I use the anonymous function and pass in the
05:16code that I want to have executed.
05:18So the JavaScript interpreter doesn't have to fire up a separate instance of
05:22interpreting some code in a completely different scope. I'm just passing in the
05:27code that I want called, and this is much, much more efficient.
05:31Let's move on. In this example I want to show you a way to get better
05:34performance out of your setTimeout() and setInterval() functions. Don't pass
05:38strings to these guys. When you're calling things like setInterval or
05:42setTimeout, you have a couple of options. You can pass strings which indicate
05:46the code that you want to be called. And I see this all the time, especially in
05:50setTimeout. I'll see examples of scripts that pass in multiple statements to be
05:55executed every so often.
05:58This is very inefficient. Pretty much for the same reason in the previous
06:01example where we avoided using the new Function constructor, because the
06:05JavaScript interpreter has to interpret this code that you pass in, and that's
06:08not very efficient.
06:10The way you fix this is once again, pass functions instead, and in this case
06:15you can use either anonymous function or a function you've declared somewhere
06:18else. So setInterval not only takes a string, but it also takes a function that
06:22you've declared. So instead of calling the displayData string, I've declared a
06:26function named displayData(), and I pass that function into setInterval().
06:30Similarly with setTimeout(), rather than passing in these individual statements
06:34that I want executed, I put them inside an anonymous function and then pass
06:38that to setTimeout() instead. This is a much more efficient way of getting
06:42better performance out of these two functions.
06:45In JavaScript, you will see string concatenation a lot, because a lot of
06:49JavaScript deals with manipulating text content. One of the most common
06:54operations in JavaScript for working with strings is string concatenation.
07:00So when you're concatenating strings together, instead of using the + operator for
07:04a lot of strings, that gets really inefficient really quickly because of the
07:09way the interpreter works. It has to create some temporary strings to hold the
07:12results. What you want do instead is use the += operator.
07:17So in the top example I've got a variable called sNewStr and it's adding a
07:21whole bunch of strings together. If this goes on for a while, like several 100
07:26strings because they're inside some loop or something, that gets pretty inefficient.
07:30So what I have done is I've written the example below to clear the sNewStr,
07:35like I do in the top example, but instead of using the + operator over and
07:38over, I just use the += operator for each string I want appended. It turns out
07:42that this a faster way of concatenating strings in the modern JavaScript engines.
07:48Use the innerHTML property if you are processing a large chunk of markup
07:53instead of using the DOM functions. Now, prior to the Firefox and Mozilla
07:58browsers, innerHTML was introduced in Internet Explorer 4 along with a few
08:04other properties, outerHTML and inner and outerText. It turns out that even
08:09though this is not a standard property that's endorsed by the W3C, all the
08:14modern browsers now support innerHTML, including Firefox.
08:17Now, the other three properties are not supported outside of IE, so don't go
08:20using those, but innerHTML is great. The reason for this is because browsers,
08:25as you might guess, are pretty efficient at parsing HTML code. So if you're
08:30working with large chunks of HTML markup inside your scripts, this can be a
08:35much faster way than using the DOM methods.
08:38So I've got a simple example down here that shows how to use it. Rather than
08:42building up your content for the element here and using the DOM functions like
08:47appendChild and createElement and so on, I'm just saying hey element, set your
08:51innerHTML to, and then this string which is a <div><p> with a paragraph inside
08:56of it. The browser will parse this and then set the resulting HTML to be the
09:00innerHTML of this element. This is a lot faster in many cases than using a
09:06whole bunch of DOM methods.
09:07Now finally, one final tip on DOM performance. Avoid making large scale DOM
09:13changes one at a time inside loops. The reason you want to avoid this is
09:18because every change you make to the DOM causes the document to be re-parsed or
09:23we call document reflow. So instead of doing this, make changes to a temporary
09:28object and then copy the results back into the document.
09:32So let's take a look at an example. Now, in this example what I'm doing is I'm
09:36creating content that's going to go inside this <div> right here. So I get the
09:41element that I'm going to modify, which is the <div> inside my document using
09:45the getElementById DOM function. I have a variable here called the oClone and o
09:51stands for object. So I'm making a clone of the original object using the DOM
09:57function, cloneNode, and true means don't just clone me, but clone everything
10:03inside my tag as well.
10:05What I'm going to do, now that I have this clone, rather than working on the
10:08original element, I'm going to work on the clone instead, because when you make
10:10a clone, its not actually part of the document, its just kind of sitting out
10:15there in space and making changes to the clone is not going to cause the HTML
10:21document that you have in the browser window to reflow.
10:24So now down here in my script, imagine I have a big array of a whole bunch of
10:28strings. I'm going to loop over those and I'm going to call all these DOM
10:31methods, like createElement and createTextNode, and what I'm doing is I'm
10:35sending the oNewElem that I have created to the contents of the elements I'm
10:40creating, and then I'm adding all of those to the cloneNode.
10:43So when I'm done, I'm going to say hey, original element, get your parent node
10:48and replace the original with the clone. So this will cause one document reflow
10:54rather than however many strings there are in this array. So this is a much
10:59more efficient way of making changes to the DOM.
11:03That brings us to the end of the section on improving performance. Now let's
11:08take a look at ways you can create reusable namespaces and modules for use in your scripts.
Collapse this transcript
Creating reusable modules
00:00One of the best ways to create JavaScript that you can reuse across multiple
00:05projects or multiple sites or pass out to other people is by creating modules
00:10with namespaces. And that's what we're going to look at in this section. So
00:14namespaces are a way for creating reusable pieces of code that can be used
00:19together and don't collide with each other.
00:22So you can imagine if you're using code from somebody else that you've
00:25downloaded from the Internet somewhere or that someone else has created, and
00:29they're using functions and variables that are the same names as the functions
00:33and variables that you're using, that's going to get really messy, really quickly.
00:36Namespaces provide a way for avoiding that problem.
00:41Now, JavaScript does not have a built-in way to do this. So you have to
00:45approximate it using JavaScript objects and by following a simple naming
00:49convention. There is a couple of different ways to do this and I'll show you
00:53the way that I use. Then you use the namespace to hold all of the objects and
00:57functions and variables and so on that you want to use in your scripts and your pages.
01:02To see some examples of this, you should visit a website called OpenJSAN.org.
01:07This is a website that contains a whole bunch of pre-built modules that others
01:12have built and want to share and have posted online to be downloaded. Let me
01:18switch over to the site so you can see it.
01:21This is the JSAN site, it's the JavaScript Achieve Network, and essentially
01:25it's a giant library. You can see all the distributions are over here. These
01:29are all the libraries that folks have uploaded that you can download and take
01:34advantage of in your own scripts.
01:36Each one of these is a separate module, and once you've downloaded it and
01:40extracted it from its archive, you can then include the scripts in your pages,
01:44without having to worry about their functions and variables colliding with
01:49yours. So let's go back to the slide, so we can see how to do this.
01:54So to create your own namespace and module, what you're going to do is declare
01:59a global object that is uniquely named that's going to hold the contents of the
02:03module. So you might be saying okay, well, how do I make sure that the name I'm
02:07choosing is unique.
02:09Well, I've found that using reverse domain names usually works pretty well. So
02:14for example, I've got the domain JoeMarini.com and no one else should have it.
02:19If someone else has it, I'm probably going to want to go and call my ISP to find out why.
02:22So what I do is I take my domain name and I reverse it. So instead of
02:27JoeMarini.com, I name my object com _joemarini or I could do something
02:33different. I could name a top-level object com and then have an object called
02:37.joemarini on there. Just to make things simple, I've chosen this syntax.
02:42So this line of code here, test to see if com_joemarini exists. If it doesn't,
02:45it creates a new empty object using this braces syntax. Otherwise, if it does
02:49exist and its type is not object, then something went wrong somewhere.
02:54And using exceptions, which we'll cover later, I'm going to raise a little error
02:58here that says Hey! com_joemarini is not an object. You should probably go
03:02investigate that.
03:02Now, if all that works out well, I can just go ahead and start naming some
03:07properties on my top-level namespace here. Now, a couple of properties I always
03:12include are sNAME and sVERSION and this is so others can check to see what the
03:18name of the module is and what version they're using and test for
03:21compatibility, that kind of stuff.
03:23So this is again, there is a couple of different practices that different
03:26namespaces follow. Yahoo, for example, does not use this com_ syntax. They just
03:32have a namespace called Yahoo. Just find the one that works for you.
03:36So after I have created the namespace object and I have declared these common
03:40properties right here, I can just go ahead and put my functions and properties
03:44on my top-level object, and now I don't have to worry about other people
03:49defining functions, named things like method1 or variables named aProperty1 or
03:54anything like that, because since they're contained inside my top-level
03:58namespace object here, they can go ahead and name their functions whatever they
04:02want, and as long as they're inside their own namespace, or even if they're not
04:06inside their own namespace, these functions are not going to collide with
04:09anybody else's.
04:10So, I have now taken my code and written it in a way that is modular and I can
04:16hand out to other people, and I don't have to worry about my functions
04:20interfering with other people's functions or ones I've written myself.
04:25So that brings us to a point now where we've seen how to use some better coding
04:28practices to get better performance and take advantage of the built-in
04:31capabilities of the browsers. We're at a point now where we can start doing
04:36some real code and move on to some of the more advanced features of JavaScript language.
Collapse this transcript
2. Understanding JavaScript Exception Handling
Understanding exceptions
00:00If you've ever tried to write a large amount of JavaScript and handle any
00:06errors that happen inside your scripts, you've properly run into a problem that
00:10a lot of JavaScript authors run into that the error-handing code quickly
00:14overwhelms the logic of the function that you're trying to write in the first place.
00:18So to fix that problem, we're going to take a look at something called
00:21exception handing in the JavaScript language. Now, exception handling has been
00:26around in other programming languages like C++ and Java for a long time, and
00:31the JavaScript language recently with the introduction of Version 1.4 got the
00:36same kind of capability and that's what we're going to look at in this section.
00:39Let's begin by looking at what exceptions are. Exceptions are a way of dealing
00:46with errors in your scripts and conditions within a script that would for
00:50whatever reason interrupt the normal execution of that script. Exceptions
00:56happen when one of two things occurs. First, somewhere in the browser a runtime
01:02error occurs within a script, which causes the browser itself to what's called
01:06raise an exception.
01:08So an example of this might be, you try to divide a number by zero or something
01:13like that. So that's a problem where you've written some code that causes the
01:17browser to have a problem, or a script explicitly throws its own exception
01:24using the JavaScript Throw statement.
01:27So one of those two things are going to cause an exception. Exceptions are
01:29handled in your code using the statements try, catch and finally.
01:35These are relatively new additions to the JavaScript language and these are what you use
01:40in order to handle exceptions that occur in your code. So let's take a look at
01:46how exceptions work.
Collapse this transcript
Using exceptions
00:00The way that exceptions work is you enclose the code that you want to execute
00:05normally inside of a try block, the word try with a couple of braces. The code
00:13in exception usually will execute normally, but if an exception happens, then
00:18the execution of the script will jump to the nearest catch block, which you can
00:24see written below.
00:25So the word catch with a variable in parenthesis, which is the exception, and
00:31the code inside those braces are only executed if something goes wrong in the
00:36try section. One of the functions in there throws an exception or you did
00:41something that caused the browser to raise an exception. If one of those two
00:44things happens, the flow of execution will jump to the catch block, and that
00:49little variable e there, or whatever you name it, will contain
00:52information about the exception that you can inspect and maybe show to the user
00:57as an error message.
00:58The code in the finally section at the bottom there are always executed,
01:02regardless of whether there are any problems in the try section or regardless
01:06of whether the catch block had to execute, the statements in there happen
01:11every single time.
01:13So, now that we've taken a look at how the structure of exceptions look, let's
01:18take a look in a simple little example before we jump to a live one.
01:21So, exception handling makes code more modular and easier to read, and you're
01:26about to quit this UI. So on left- hand side, this is the old way to dealing
01:31with JavaScript errors. You'd have some variable named error code (errCode) or
01:35something like that, and you'd call a function, and the function would come
01:39back with some kind of code. Either zero, if everything is fine, or -1 or -2.
01:46If the function could return multiple errors, then you'd have to keep track of
01:49all the different error codes and you can see that that's about to get pretty
01:52unwieldy, pretty quickly. So just in this one simple example, I've got a
01:55function_a, which can return a whole bunch of different error codes. And each
01:59one of these things needs to be handled differently.
02:02So I've got, if the error code is -1, I've got handleError. Otherwise if it's -2,
02:05oh, that's another function and there is another one here for -3.
02:11Now imagine that you had multiple functions, all returning potentially different
02:16kinds of error codes and this just becomes a whole bunch of spaghetti pretty quickly.
02:21Now the modern way of doing this is to use exceptions. So, let's suppose we
02:26rewrote the same thing differently. What we've done here is inside this try
02:31section, we're calling a couple different functions as a, b and c, and if
02:36anyone of these functions causes a problem, causes an error to be raised or
02:41something goes wrong in the browser, the flow of execution is going to jump
02:45down here to the catch block where we handle the error.
02:48Then after than happens or if everything goes fine in the try block, the
02:53finally section will then execute and then we can clean up and clean up can do,
02:59whatever we need to do. This is optional. One of the things I want to point out
03:03is that, the catch section and the finally section are optional, but you have
03:09to have at least one. You can't have a try just standing by itself.
03:13You can do try, catch, you can do try, finally, you can do try, catch, finally
03:17like I've got here, but you can't just have a try by itself, you've got to pair
03:21it up with one of these guys down here.
03:23As I mentioned earlier scripts can throw their own exceptions using the throw
03:28statement. And you can throw an exception as a string or a number or an object.
03:35In fact, JavaScript defines a new object called the Error object, and the Error
03:40object is a predefined JavaScript object that contains information about a
03:46JavaScript exception.
03:47Now the properties are slightly different between Internet Explorer and
03:52Firefox, but the most important ones name and message are common to both. So
03:59when an exception happens and the catch block executes, the contents of the e
04:04variable, if it's an error, it could be a string or a number. But if you throw
04:09an error object, then the e variable inside the catch block will be this kind
04:15of an object here. You can check the name and message properties to see what
04:20happened and what went wrong.
04:21So the name will usually be the type of the exception and usually that's just
04:24going to say Error because that's the name of the class and the message will be
04:27the string that was passed into the Error constructor function right here. So,
04:32an error occurred in this case.
04:35So now it's time to actually look at an exception example in real life. So, let
04:40me switch over to the code and we can see an example of how to create and throw
04:45our own exceptions.
04:46So you see here we have the empty HTML file, this is going to serve as the test
04:51bed for our exception extravaganza. So I'm going to start off by putting a
04:55script in there. Let's say script type = "text/javascript".
05:03So the first thing I'm going to do is I'm going to write a function that
05:05retrieves a name from the user, and I'm going to call that function getName.
05:13This function's whole job in life is basically going to be to prompt the user
05:16for a name and show us what the name entered was.
05:19So I'm going to say var sName = prompt(), and the prompt function is going to
05:27say Enter a name: and there is no default value. And I'm going to say
05:35okay, alert("You entered: " + sName). Pretty simple, pretty straightforward.
05:47Now, what might happen is the user might enter nothing or an empty string, so
05:53we need to catch that part. So we're going to say hey, if name is null, or the
06:00length of name is zero, then we are going to throw a new Error exception and
06:13we're going to have the Error exception say "Name was not in a permitted form".
06:24So let's see what happens. We're going to try this out now and I'm not going to
06:29have any try or catch or finally block, I'm going to say window.onload =
06:39getName. Now let's browse and see what happens and we open up. There is the
06:45prompt and I'm going to type in Joe, and yup, it looks like everything is working fine.
06:51So let me refresh one more time. Now I'm just going to hit Cancel and enter nothing.
06:55You can see that what happened was when I hit Cancel, I didn't enter
06:59a name. So that caused an exception to get raised using the throw statement.
07:04If we look at the details, you can see that the error that was thrown was, name
07:09was not in a permitted form and it shows me the line and the character index,
07:14and the URL of where the exception happened.
07:18Now, this is not very user-friendly. So, let's see if we can improve the
07:23exception handling. So, I'm going to get another function here called function
07:26testException() and testException is going to try to call the getName function
07:42and we're going to catch an exception that happens and inside the catch
07:51we're going to say alert (e.name + ": " + e.message).
08:04So remember earlier, I was saying that the name and the message fields are both
08:07common to Internet Explorer and Firefox. So this should work cross-browser.
08:12And then, in the onload, I'm going to say testException. Now let's try to run our
08:21script again. I'm going to browse this. Up comes the browser, there is the
08:26prompt. I type in Joe, okay that part is still working fine. Let's refresh.
08:32This time I'm just going to say okay, without entering a name, and you can see
08:35that this time we get the alert in the catch blocks as error. Name was not in a
08:41permitted form, okay.
08:42So, a couple things I want to point out here. First, we interrupted the
08:47browser's alert process, by catching this exception and then alerting what
08:52happened. And you will also notice that when I entered the name properly, this
08:58throw statement didn't execute and we got to the alert just fine.
09:02However, when an exception happened by throwing it here, this alert statement
09:07never executed. The reason it never executed was because the error happened
09:11right here and then as a result of the exception being thrown, the control of
09:17the script immediately jumps to the nearest catch block, which, I want to point
09:21out was not anywhere in this function, it was actually up here.
09:26So this function, testException called a function which caused an exception and
09:31the exception was caught up at this level here. There is nothing about catching
09:35the exception here in getName itself.
09:37So, as I said earlier, you don't need to have the catch, you can have either
09:41catch or finally. If I took the catch out, let's take that out for a second and
09:47well, let's see what happens if I don't put anything else in there. So if I say
09:49just by itself, I just try to browse this, you'll see that there is a problem,
09:54and if we show the details, you'll see, oh! The browser is expecting a catch
09:58statement there. So you can't just have try by itself.
10:00So let's go back in here and we took out the catch, but you can't do like a
10:04finally by itself and I'm not going to have any kind of code inside the finally
10:10block. So now what I have is the try, the getName and just the finally. So,
10:15let's see what that does.
10:16I'm going to browse it, up comes the prompt, type in Joe. That works fine.
10:22Working up again, this time I'm not going to do anything. I'm going to say OK,
10:26and you can say oh! Look Name was not in permitted form, so the browser's
10:32exception handling still works, and now, when I click OK, the code in the
10:36finally block will execute as well.
10:39And just to prove to you that it's cross -platform, we're going to go ahead and
10:43browse this with Firefox. Okay, and you can see we would enter a name, and that
10:49works, I'm going to refresh. I'm going to enter nothing, and you can see in the
10:55case of Firefox, it's going to open up the error console. You can see there it
10:58is. Name was not in a permitted form.
11:01Or I can go back in and put my catch statement back in, I'm going to Undo,
11:08okay. Now let's browse that with Firefox. Okay, there is the prompt. I'm going
11:16to enter nothing, and oh! Look, we get the alert. Name was not in a permitted form.
11:21So hopefully this gives you some taste of how you can do better error handling
11:27inside your scripts using exceptions. You can see that we were able to separate
11:32out the function and script logic from the places where we handled the errors.
11:37This results in much cleaner script, much easier error handling and code that's
11:43just easy to maintain and read.
Collapse this transcript
3. The Modern Event Model
Understanding the modern event model
00:00Any kind of practical and effective JavaScript programming has to deal with
00:04events and the modern browsers provide a better event model than the event
00:10model you are probably used to working with which consists of putting event
00:13handlers directly on tag such as onClick and onLoad and such. So in this section,
00:19we are going to see how to use the Modern Event Model to handle events
00:23in a much more object oriented and less intrusive way into your markup.
00:29So the modern browsers have provided a newer way of handling events that allows
00:34for making code more readable and reusable and also making it a lot easier to
00:39debug your code.
00:40The DOM Level 2 Specification defines some new methods you can use to add and
00:47remove events on objects in your page. Internet Explorer has slightly different
00:52functions and properties because they implemented this model before the DOM got
00:56around to specifying it but the model is essentially the same and we'll cover a
01:01way to make your event handling code work cross browser.
01:06The nice thing about this model is that events can be chained together and can
01:10be independently added and removed from objects. Now what I mean by that is
01:15rather than having to write one event handler in which all of your logic takes place,
01:19you can write smaller, more independent event handlers, wrench them all
01:25on the same object and they will all be called in order when a given event
01:29happens. Again, this leads to more reusable code because you don't have to have
01:34one giant function to handle a single event; they can all be called in order.
01:39And you can turn these event handlers on and off as you need them and we'll see
01:44an example of how to do that.
01:45Let's begin by looking at the event flow in the Modern Event Model.
01:49Certain types of events pass down through and then bubble back up through the element tree
01:55until they are either handled by an event handler or they just pass up to
01:59the top of the document and to see an example of this, suppose we have a
02:03document that has some content that looks like this. We have got a div with an
02:07unordered list in it with some list items. And suppose further that a click
02:11event happens on this list item.
02:13Now in the past, you would have to register an event handler using the onClick
02:18on each one of these individual list items if you wanted to handle click events.
02:21In the new model, however, the event can be handled in any of these places.
02:25You can handle the event on the list item itself or the parent <ul> tag
02:31or the div or the body.
02:33Now, not all events bubble up like this but the mouse ones do. The key events do,
02:38but things like blur and focus, they don't bubble up. So the nice thing
02:43about this is that you can define one event handler somewhere higher up in the
02:47tag hierarchy and handle all of the events for all of that item's child elements.
02:53Another way of looking at this is by looking at a stack of the elements we had
02:58in the previous document. Events go through phases. There is the capture phase,
03:04there is the at target phase and there is the bubbling phase. So let's again
03:09suppose that I have got my mouse and I click on this list item right here.
03:12What's going to happen is the mouse event is going to travel down from
03:16the body, through the div, through the unordered list, to the list item.
03:20This is called the capturing phase. So if I have defined an event handler, say for
03:25example, on this ul tag or this div tag, I can actually capture and handle
03:30the event before it ever gets to the list item. Once the event reaches the list item,
03:34it's called the at target phase. Now this is equivalent to defining an
03:39onClick handler directly on the list item itself. So that's pretty much
03:43the method that you are probably used to.
03:45At this point, I can handle the event directly on the list item. Now once the
03:49event has reached the list item, if it hasn't yet been handled, it begins to
03:54bubble back up through the tree. So again, this is after the event has already
03:58been to the list item, and now it's traveling up back through the list,
04:02back through the div and back to the body. So using the DOM level event model, I can
04:07handle the event either before it gets to the item, when it gets there or after
04:12it gets there and starts traveling back up again.
04:14Now Internet Explorer does not implement the capturing phase. In the case of IE,
04:19you are going to want to handle the event either when it gets to the
04:22at target phase or in the bubbling phase. In order to use these new events,
04:27you are going to have to define event handlers for your objects and that's what
04:30we are going to talk about here.
04:31Now the old way of doing this was, you can see on the left. There is the
04:35window.onload event and usually you would have some function or something like
04:41that or more typically, you would have an element somewhere in the document and
04:45you would have an on event handler that looks something like this.
04:49This is the old way of doing it and it's not very extensible, it's not very
04:52readable and it's certainly not best practice for separating behavior from your code,
04:57which we'll talk about little bit more in the next section but the general idea
05:02is that you don't want to mix behavior with your code, the same way that
05:05you don't want to mix style information with your code. This is why we use
05:08external style sheets and classes rather than putting inline styles. So putting
05:13an inline event is not really the modern way of doing this.
05:16The modern way of doing this is on the right. What you do is you call the
05:20addEventListener method for DOM Level 2 events or in IE, the example below,
05:27the Attach event, and you call one of these two functions on the element that
05:32you want to have the event added to.
05:35In the case of the DOM level 2, it takes the name of the event load and in IE,
05:40you have to put an 'on' in front of it and it takes the function that you want
05:45to have called when the event happens. In the case of DOM Level 2,
05:49this argument here can be false or true. This determines whether or not you want to
05:53have the event handled during the capturing phase. Now remember IE doesn't
05:57implement that so there is no equivalent argument here.
06:00Okay, so to make this work across browsers, you are going to have to have some
06:03way of registering events cross browser. So up here at the top, we have got the
06:08functions you use in both the DOM and IE. So for attaching events to elements
06:14in the DOM, you use addEventListener and then for turning those event handlers off,
06:17you use removeEventListener. And in IE, you have got the same thing,
06:21attachEvent and detachEvent.
06:23To do this in a cross-browser fashion, you can see I have written a small
06:26utility function here called addEventHandler and it takes the object that
06:30you want to have the event registered on, a string which indicates the event that
06:34you are trying to handle and the function that you want to have handled.
06:37The way that this works cross browser is the first thing we do is check for the
06:42type of window.event. Now this only exists in IE, so if this is not undefined,
06:48then we know we are on IE and we call the attachEvent function. Now IE expects
06:52the word 'on' to be in front of the event name. So we pass in the event name as
06:56if we are going to use the DOM level 2 but we prepend it with the word 'on'
07:01and we pass in the function handler that we want to have handle it.
07:04In the case of DOM Level 2, however, we have simply call addEventListener and we pass
07:08in the string and we pass in the function that we want to have handled and
07:12in this case, I'm defaulting to true for capturing but you could also modify this
07:16function slightly to pass this in as a fourth argument and just not use it in
07:19the IE case.
07:20In the case of handling the event, the function you would pass in for fnHandler
07:25would look something like this.
07:26Now DOM Level 2 will pass in an argument that represents the event that
07:30happened and that's e right here. Now IE doesn't do that. IE has a global
07:34property on the window object called event and that's this guy right here. So,
07:38the way to write it cross browser is to have a local variable named something
07:41like evt and if e is null, then window.event will be used instead.
07:46So that's the IE case. Otherwise it will just use the argument that was passed in.
07:50The event model defines new properties and functions so let's take a look at those.
07:55For the DOM, the most important ones I have listed here. The target
08:00property that gets passed in that e argument is the node on which the event
08:04originated. So in the case of our example, if I clicked on the list item tag,
08:08that's the element that would be represented by target here. Type is a string
08:11that indicates the type of event. It is a Click or KeyPress or what have you.
08:15The bubbles property indicates whether or not the event is going to bubble up.
08:19So it's a Boolean to be true or false. Cancelable is also a Boolean.
08:22It indicates whether you can cancel the event or not. This is what you use to
08:26cancel the default behavior that the browser is going to implement when the
08:30event is handled by the default event handler say for links, for example.
08:34currentTarget is a property that indicates the node that the event handler
08:39that's currently running is attached to. So if you need to know, for example,
08:43in your event handler, which node that event handler is attached to, you can
08:46look this property. Unfortunately IE doesn't have a property like this.
08:49So it's only available in DOM Level 2.
08:52The eventPhase property indicates what phase the event is currently in, whether
08:56it's capturing or at target or bubbling, and timeStamp indicates when the event occurred.
09:01There is a couple of methods also. There is preventDefault(), which prevents
09:05the browser from performing any default action. So if Cancelable is true,
09:10up here you can call preventDefault() so for example a Hyperlink won't activate
09:14when you click on it.
09:15stopPropagation() stops the event in its tracks and you can use this either
09:20during the capture or bubble phase to stop the event from going any further.
09:24IE also has some properties, we'll take a look at those. Source element is the
09:28node on which the event originated. So that's analogous to the target event
09:32over here in the DOM Level 2. Type is the same as for DOM Level 2. So it's a
09:36string that indicates what kind of event it is. Return value, this prevents the
09:42browser from performing whatever the default action is. So you can think of
09:46this as an analogous version of stopPropagation in DOM Level 2 and cancelBubble
09:51stops the event flow.
09:52Now for IE since they don't have a capture phase, this only effects the bubble phase.
09:57Okay, so now that we have seen what properties and methods there are and how to
10:00register event handlers, let's look at a few examples.
Collapse this transcript
Using simple event handling
00:00Let's take a look at a simple example of how you would register an event
00:04handler to handle a simple event like a click event.
00:08So up here in my script section, I'm going to write a function and I'm going to
00:14write the cross-browser function that we had earlier in the slide. So I'm going
00:19to write function addEventHandler and this function is going to take a couple
00:26of arguments. It's going to take the element that we want to register the
00:30function on, the string that represents the event, the function
00:37that we want to have register the handler and I'm going to pass in a
00:42Boolean that indicates whether we want to use capture in DOM Level 2.
00:46Okay, so now we say if (type of (window.event) != "undefined"), then we are
00:58going to call the attachEvent version because this is IE and we are going to
01:07prepend the on with the event and the function you will want to have called.
01:16Otherwise, we are in DOM level 2 so we are going to call addEventListener and
01:28we are going pass in the event along with the function we want to have called
01:35and the Boolean that indicates whether we are using captures.
01:41So now we have written the cross- browser event registration code. What we need
01:45to do now is use this in order to setup the event handler for clicking on this
01:51link down here. So what we want to have happen is when this link is clicked,
01:54we are going to display a little alert to the user. So the first thing we are
01:59going to do is call addEventHandler and I'm going to call that on the window
02:02object and I want that to happen on the load event and we are going to name our
02:08functions setUpClickHandler and we'll call false for using the capture.
02:17So now we need to write that function. So let's write the function
02:21setUpClickHandler(). So this is the function that gets called when the window
02:31loads. So what we are going to do here is call addEventHandler and we are going
02:37to call this on the element for the link right here. So we are going to say
02:42document.getElementById and the id here is clickLink. I'll copy and paste that
02:50to make sure it's right and we want that to be called on the clickEvent and
02:58we want to call a function onLinkClicked, which we'll write, and once again we'll
03:06pass in false for using capture, okay.
03:09So now we have written the function to setup the link handler, and let's write
03:12our last function and this is going to be function onLinkClicked.
03:19And remember that takes an argument which is going to be the event in the DOM, so Firefox.
03:25And is it the same name? Yes, onLinkClicked. We are not going to use that
03:30argument for now. We are just going to say alert ("You clicked the link"), okay.
03:37Now you might be saying to yourself. Wow, you know, this is pretty verbose.
03:41In the past I would just simply put onClick on my anchor tag here. The reality is
03:46that this is a simple example but as you get into more advanced event handling,
03:50this will become a lot less verbose, because typically you will have a function
03:54like this somewhere in a library of code that you are using to register your
03:58event handlers and this you will probably only need to write once.
04:02The real work is done in places like this. And one of the things that you will
04:06find is that the benefits of being able to debug and have your event handling
04:11code separated from your markup, those benefits far outweigh the little bit
04:16of extra of typing you need to do and little bit of extra code you need to write
04:19in order to have the Modern Event Model.
04:21Now that we have written the code, let's save this and let's go ahead and
04:26browse it and see what happens. Okay, so here is the document and we are going
04:32to click the link, and when I click, it says hey! You clicked the link. Okay,
04:35so everything seemed to work.
04:37So this was a pretty simple example. You see what we did was we wrote the
04:41cross-browser version of the event registration code and then used that to
04:45register a link click event in the browser and just to make sure it works cross browser,
04:50let's go ahead and browse it with Firefox as well. I'm going to click
04:55on it and you can see, You clicked the link.
04:57So now we have a cross-browser way of registering event handlers and responding
05:02to the events. So let's take a look now at a slightly more advanced example.
Collapse this transcript
Dealing with dynamic events
00:00In this example, we are going to see a slightly more advanced way of handling
00:04events and this is where the power of the Modern Event Model really becomes apparent.
00:08I have taken the previous example, where we just wrote a simple event handler
00:12and I have modified it slightly. So you can see I have added a checkbox down
00:15here. We are going to use this checkbox to turn on and off the event handler
00:19for the link right here.
00:21So let's go to the code and see how that works. Now, I'm starting from the
00:26previous event, all the code that we have already written. There are a few
00:29things I need to add however. You can see that I have written an event handler
00:34for the window that's still there and we are going to setup the click event.
00:37Now the click event, however, is going to behave a little bit differently from
00:40the previous example. We are handling the click event for this case not on the
00:44link itself, but on the checkbox because the checkbox is going to be used to
00:48turn the event on and off.
00:50So for the click handler on the checkbox, I have a function we need to
00:54write/called onEnableClick. So let's go ahead and write that function right
00:58now. I'm going to write function onEnableClick and onEnableClick is a
01:06particular argument because it's an event handler. So in this function, what we
01:11are going to do is turn the event on and off. So we are going to get the target
01:16of the event, which is the checkbox. So we are going to say var target =, and
01:22I'm going to write a little cross- browser function here called getEventTarget
01:26because this is a useful function that you can use in your code to handle
01:33cross-browser events.
01:34So let's go up and write that function and that function is called function
01:38getEventTarget(e) and we are going to pass in the event, and that's given to us
01:43by the DOM if there isn't one and all we are going to do in getEventTarget is
01:47something like this. if (window.event != null) return window.event.srcElement
02:02else return e.target.
02:07So now regardless of which browser we are in, we'll get the right target given
02:12the event. Let's go back to onEnableClick. So what we need to do now is check to see
02:18if the checkbox's checked property is on. And if it is, we are going to
02:22enable the event. Otherwise we can turn it off.
02:24So, we'll say if (target.checked) then addEventHandler on
02:34document.getElementById('clickLink'). And we want to handle the click event and
02:50we are going to write the function onLinkClicked, there it is, and we'll pass in
02:55false for capturing.
02:59Okay, so that's great if the checkbox is checked. But if the checkbox is
03:04unchecked, we want to turn the event off. So we have to have a counterpart to
03:09addEventHandler. So we are going to go up here and write another cross-browser
03:13function that's the counterpart of addEventHandler. We are going to call it
03:17function removeEventHandler and it's going to take the same arguments, okay.
03:34And we are going to say, well, pretty much it's going to be the same code. So
03:39we are going to just copy this, put it in here and we are going to just call
03:44the counterparts of the IE and DOM functions. So instead of attachEvent, it's
03:48going to be detachEvent and instead of addEventListener, it's going to be
03:54removeEventListener, and you need to pass in the same arguments to detachEvent
03:59and removeEventListener that you passed in when you called attachEvent and
04:04attachEventListener. That way the browser knows specifically which function you
04:09are referring to attach or detach or add or remove.
04:13Now we can go back down here into the onEnableClick method and we can say else
04:22removeEventHandler and document. GetElementById. That's going to be the
04:30clickLink and we are removing the click event. We are removing the
04:36onLinkClicked function and we need to make sure we pass in the same value for captures.
04:42Okay, that should be all we need to do. So let's go ahead and save this. Now we
04:48are going to bring it up in the browser. Now you can see the checkbox is
04:50currently off. So when I click the link, nothing is happening. Now when I check
04:55the checkbox, now when I click the link again, and you can see that the event
04:58is now enabled. So it says "You clicked the link." Now I'm going to turn it off
05:01again, I click the link and you can see nothing is happening.
05:04So this is a way to turn events on and off dynamically. So once again, let's
05:09make sure it works in both browsers. We'll go back in here, and say Browse With
05:14> Firefox. I'm going to bring up the Firefox version, you can see that I click,
05:19nothing is happening. I turn on my checkbox, and click again, now the event is
05:23enabled, turn it off and now it's disabled.
05:27So this is where the power of the DOM event model really starts to become
05:30apparent. You can see that you can turn events on and off dynamically and you
05:34don't have to modify your onClick inline event handlers or anything like that.
05:39It's all done in script and it's all separated out from your markup code.
05:43Okay, now that we have seen how to do this, let's move on to a slightly more advanced model.
Collapse this transcript
Handling complex events
00:00In this example, we are going to look at some more complex event handling using
00:05the Modern Event Model. So you can see here I have my document open and I have
00:09got three divs and each one is embedded inside the other one. So I have div 3 here,
00:14I have div 2 here and I got div 1 right here at the top.
00:17So let's take a look at the source. And what you can see is down here in the
00:25source code, I have got the divs inside the body element and I want to point
00:29out that there is nothing in here that says anything about event handling on
00:32any of the divs.
00:33So right after that we don't have any event handling code attached to these
00:37elements, which is a good practice. So here is what we are going to do in this
00:41example. We are going to show how to use the capture in DOM Level 2 to trap
00:47events before they get to the target that they are going to. And we are also
00:51going to see how we can stop events by using the cancelBubble and
00:56stopPropagation methods that are provided by the DOM Level 2 and the IE event model.
01:03So you can see that I have already written a bunch of code. This is code that
01:06you have probably already seen before. We have got the cross-browser
01:11addEventHandler model here at the top. We have got our cross-browser
01:14getEventTarget and we have also got some event handlers registered for the divs
01:20and the body as well. Those event handlers are registered here in the
01:25initializeHandlers function and that is called from the addEventHandler
01:30function here which when the window loads will register all these handlers.
01:35So you can see that we are registering the events on the div, the body, we are
01:39looking for the click event and we are not using capture. So before we do
01:44anything else, let's just go ahead and browse this and see what happens. So I'm
01:46going to bring this up in IE and I'm going to click on div 3. What I'm doing
01:52here is I have some alerts popping up that indicate where the event handler currently is.
01:56So right now, we are inside the Event handler for div3 and the target is div3.
02:01That's the value of the ID attribute and the type is click. So I'm going to say
02:05OK. Now you see we are in the Event handler for div 2 and the target was div3
02:10and it's a click event. And now we are in the handler for div 1, same
02:14information and now we have traveled all the way up to the body. So this is an
02:17example of watching an event bubble up from the target to the top of the document.
02:24So let's go back to the source code really quick and you can see that in each
02:29of the event handlers -- I'm going to start with the div 3 handler, I have got
02:33a string here that's taking the information from the event object and making
02:39use of some of the information that's available in the event object along with
02:42the document itself.
02:44So using the target that came back from our cross-browser getEventTarget
02:49function. I'm getting the id attribute that's on it and adding that to the
02:53string and in the event where we have the type property that is a string. That
02:58indicates what type of event it is. That's right here. So in the case of the
03:03eventPhase, now this is the DOM Level 2 or Firefox version. We are going to add
03:07the phase on the end.
03:09So let's see what that looks like in Firefox. So I'll bring Firefox up. So I
03:17want to go ahead and click on div 3. So you can see that now here we are in the
03:22Event handler for div 3 and the target is the same, it's a click type and the
03:25phase is 2. Now you can call for div2 and the phase is 3. So phase 2 means, at
03:33target whereas phase 3 means now we are bubbling. These are constant values
03:37defined by the DOM Level 2 specification and here we are on div 1;
03:42now the phase is 3 because we are bubbling up and the body of phase 3.
03:46So you can see that the phase was different when we had the event handler
03:49running on div 3 versus the event handler running on divs 2 and div 1 and the
03:54body. Okay, let's go back to the code now and slightly modify this example to
04:00handle the capturing phase. So remember capturing doesn't exist in Internet
04:04Explorer. And nothing bad will happen if you call it in the addEventHandler
04:09function but just to be cross browser, I'm going to add an if statement here.
04:14if window.event-- Not window.event. That means we are not in IE anymore.
04:25I'm just going to make copies of all these event handlers right here, paste them in
04:30and I'm going to pass in true for the capture.
04:39So now each of these event handlers is also going to be called for the
04:43capturing phase in Firefox as well as the bubbling phase. Okay, so let's see
04:47what that did to our example. I'm going to go back in browser Firefox. So now
04:54I'm going to go ahead and click on div 3, now you can see that what happened is
04:57slightly different. Now we are in the event handler for the body. So the body
05:00is being called first and you can see that the target is the id attribute for
05:03div 3, so we know where the event is going to go, we are just not there yet.
05:07We are in the event handler for the body right now. And you can see here type is click.
05:11Now the phase value is 1 and the value of 1 means we are in the capturing event
05:16of the event. So now we are going to travel down from the body to div1 to div2,
05:21so you can see, okay now we are in div1, still in the capturing phase. Now we
05:25are in div2, still in the capturing phase.
05:28Now we reach div3 and when we reach div3 that's where the event is going.
05:32That's div3, the target is right here. The phase has now changed to 2. That
05:36means that we are at the target. So we are now in at where the event is going
05:41to reach its destination.
05:42So now I'll click OK. Now we are going to start bubbling back up again. So now
05:45here we are on div3 phase is still 2. Now we are traveling back up to 3 again.
05:50So now we are in div2. Now the phase has changed to 3, so now we are bubbling.
05:54And then back up to div1 and then back up to the body.
05:56So you can see that how adding the capturing parameter to our addEventHandler
06:02has changed the behavior. So now we are getting a hold of the event before just
06:06to where it's going while it's there and while it's coming back. That only
06:10works in the DOM Level 2 capable browsers such as Firefox.
06:15So what we are going to do now is we are going to go back and we are going to
06:17see how we can prevent the event from going any further. We are going to stop
06:21it at its tracks and to do that I'm going to write a cross-browser function
06:27called stopEvent. And stopEvent is going to take an argument and take an event
06:33argument just like getEventTarget does and in fact it's going to be very
06:38similar to getEventTarget.
06:39So we are just going to copy that code and paste it in here. In this case of
06:42window event, what we want to do is not return anything. We want to call
06:46window.event.cancelBubble = true. So this will stop the event right in its
06:57tracks, in the case of IE. In the case of the DOM, remember what we want to
07:02call it is event.stopPropagation.
07:05Okay, so now we have a cross-browser function that given an event will cancel
07:16the bubbling process. In the case of stopPropagation, it will also work in the
07:21capturing phase as well as the bubbling phase. So let's put this guy right
07:26after the alert on div2. We are going to call stopEvent and we are going to
07:31pass in the raw event here. Not the one that we have got from the
07:34getEventTarget because we want to be cross-browser here. So we call stopEvent.
07:40Now let's see how that has affected our example. So let's first do it in IE.
07:43Okay, here we are. Now what should happen is the event handler for div 3 should
07:49fire, which it did. Now we are going to see the event handler for div 2.
07:54Now, things should stop here. Sure enough it did. The event handlers for div 1 and
07:59the body didn't fire because we have set the value of cancelBubble to true and
08:03in IE that means stop what you are doing.
08:04Okay, so now let's take a look at what happens in Firefox. We are at the
08:12Firefox browser. So now I'm going to go ahead and click on div 3. So now we are
08:18in the bubbling phase, we are in the body. We are in div 1, we are in div 2 and
08:25nothing else happens. In this case, we never got to the target because we
08:28didn't distinguish between the bubbling phase or the capturing phase.
08:32So we can actually go back to the code. In the case of Firefox, we can check to
08:39see if there is an event phase property. Then we can say inside this if
08:46statement, we can say if (e.eventPhase != 1). So we are not going to care about
09:01the capturing phase. We are going to say stopEvent (evt) and in the case of the
09:09Internet Explorer browser, which doesn't have eventPhase, we are just going to
09:12go ahead and call stopEvent.
09:14So now, let's go back to Firefox. So now I'm going to click on div 3, okay, so
09:22there we are on the body. There is div1, there is div2, there is div3. So now
09:28we have made it pass that div 2 blockage. It's going to start bubbling now.
09:33We have the div3 handler. There's the div2 handler. Now at this point the event
09:37should stop and it does.
09:39This is an example of how you can use some of the more advanced event handling
09:43properties in the DOM Level 2 and IE to better control how events flow and get
09:49more information about events and just write better more modular event handling code.
09:53You should have everything you need to know to go out and do this in your own code.
Collapse this transcript
4. Using Progressive Enhancement in Web Pages
Separating behavior from content
00:00Okay, in this section we are going to talk about progressive enhancement.
00:03Sometimes referred to as the separation of mark up and behavior. You may have
00:07heard of progressive enhancement before, even if you haven't, you are probably
00:10familiar with the concept. Some people call it Unobtrusive JavaScript.
00:15Sometimes it's called graceful degradation. The main idea here is that you are
00:20enabling more advanced functionality in your web pages based on the browser's
00:25ability to support it. Your code essentially detects the presence of a certain
00:31capability whether it's DOM or AJAX or some other capability and then enables
00:37that feature that needs it.
00:39So the whole idea here is that users who have less capable browsers or for
00:45whatever reason have disabled certain features like JavaScript still get a good
00:49experience in your page. While the users with more advanced capabilities still
00:53get to use those. It's basically a way of building up features from the ground
00:58up in order to support the more advanced features that are available in the
01:02browser. So let's talk a little bit about separation of mark up from behavior.
01:07You have probably already had some experience with this concept if you have
01:11gone ahead and taken your CSS code and separated that from your mark up and you
01:16have hopefully by now have removed things like <font> tags or other
01:20presentation directives from your page content. This is a bad practice.
01:25The whole idea is that XHTML content is supposed to contain just the semantic
01:30information from page and nothing about how it's supposed to be presented. So
01:35the whole idea between external CSS and not using mark up to describe
01:41presentation extends to behavior.
01:43So the idea here is you take scripts and you make sure they are stored in
01:46external JavaScript files rather than inline in the page and you avoid using
01:51things like inline event attributes like onClick equals or doing things like
01:56the href JavaScript functions. You can do this in links and anchor tags. Don't
02:01do this. The idea here is separate this stuff out into external file so that
02:06your mark up contains only the information in the page and things like
02:10presentation and behavior are external and effect the markup.
02:15Now you have probably seen code like this before in pages, right. In fact, in
02:19my examples up until now I have used them. You have <script> tag with inline
02:23JavaScript or JavaScript contained between the tags. You have probably seen
02:27examples like this where you have an anchor tag and you have got some function
02:29call with a return here or you know you have got the onClick handler right
02:34here. This is probably not the right way to do things. This is a bad practice.
02:38The better practice is to first of all make sure that your script is stored in
02:42external files and progressively build up behavior using things like the
02:47addEventHandler function, which we discussed in the Modern Event Model section.
02:52So if you haven't had a chance to go back and look at the section on the Modern
02:56Event Model, now is a good time to do that because we are going to be using
02:59those concepts here in the progressive enhancement chapter.
03:03So now that we know what it's all about and how to do it, let's take an example
03:07and see it in action.
Collapse this transcript
Using progressive enhancement
00:00Okay, so here I'm in my Design tool and see it's got a table in my page and got
00:04some information. The table is two columns. Some strings over here, some
00:08numbers on the side. It's pretty standard shopping list stuff.
00:11And I've has also got these arrows that I'm providing so the user can sort the
00:15data in the table. So let's bring this up in the browser before we go any
00:18further in and see how this works.
00:21So here we are in IE and I'm clicking the arrows, sorting my data.
00:27That's really great. So the problem however is you see as I'm mousing over the arrow there,
00:33if you look down on the status bar, it's a JavaScript link and
00:36it's calling a function called sortTable. So the problem is what if I turn off
00:40JavaScript or what if the DOM is unavailable? So let me go down here to this thing,
00:45turn Script off. By the way, if you're wondering what this guy is right here.
00:48This is the developer bar for IE and it's one of the tools I'll be
00:53talking about later on in the course. It's a really useful utility for
00:56developing and debugging your pages and I'll tell you where you can get it.
00:59But one of the things it allows me do is turn script off. So I just did that.
01:02Now watch what happens. You can see that the link is still there, but when I
01:04click on the arrows nothing is happening. So for a user that doesn't have
01:09access to JavaScript or the DOM or any of the other features they need to do
01:12this, this is something become a pretty frustrating experience. So what I'm
01:16going to do now is I'm going to turn Script back on. Let's go back and take a
01:20look at the code to see how we can fix this problem.
01:23Okay, so I'm going to close the browser and let's go over to the source code.
01:29So here's the source code for the document, here's the table with all the
01:32information in it, and here is the images with the JavaScript links, I want to
01:37go back and fix the those later. Then I have got some style information in here
01:41and I've got some JavaScript. So the first thing I'm going to do is fix this
01:47problem by creating a new file. I'm going to make a JavaScript file. I'm going
01:51to save this in the exercise_files folder. Then I'm going to put it in the
02:00progressive enhancement - 04_enhancement. I want to call this Tablesorting.js,
02:09and what I'm going to do now is copy the code out of here and paste it into my
02:21Tablesorting.js file.
02:23Okay, so now I have saved that. So now what I need to do is make this an
02:28external file. So I'm going to do is source = and I'm going to pick that file,
02:34it's that guy right there. Okay, so now I've externalized my script, and I need
02:39to do the same thing with my style sheet. So I'm going to do the same thing.
02:44I'm going to enter the title and say link rel = Stylesheet. Let's go ahead and
02:55copy all this out of here, actually cut it out, and make a new file and it's a
03:03style sheet, and we'll paste all that in and we'll save this also in the same
03:09folder. We'll call this Tablesorting.css. We'll put it there, okay?
03:26So now we have that in an external file, so let's go back to our code, get rid
03:32of the empty style and put in the href for our style sheet. And that's there
03:42right there. And we put that in quotes.
03:48We've externalized the style sheet. We've externalized the JavaScript. So
03:52before we go any further, let's make sure that this guy is still working. So
03:56I'll bring it back up in the browser, yeah, it's still working, but I'm going
04:01to go and fix those JavaScript links, because they are causing some problems.
04:05So what we need to do is -- let's bring up the JavaScript file. So we are going
04:10to go ahead and use some of the concepts we learned in the previous section on
04:14the Modern Event Model.
04:15So first thing we are going to do is write a function and I'll add event
04:23handler, and you've seen this before if you were following along in the
04:29previous section. So what this function is going to do is use the Modern Event
04:33Model to add an event handler to an object.
05:35Okay, so now we have written the event handler. What we need to do now however
05:39is get those JavaScript links off of these guys right here. So what I'm going
05:46to do is write a function that's going to on the fly modify those arrows, so
05:54that when the page loads, the sorting links are automatic setup for me. So here
05:59is what we are going to do. We are going to write a function called
06:02insertSortControls and it's not going to take any arguments. What we need to do
06:13is on the fly build up the link. You can see I have an anchor tab with enclosed
06:18image. We are going to remove the code here and have it automatically added at
06:24runtime when the window loads. Okay, so what we need to do is you see each on
06:30these guys has an ID on it, item ascend, item descend and then price, ascending
06:36and descending. So what we are going to do is in the SortControls function
06:42declare a variable called the link object.
07:31So what I'm going to do is just go back here, copy off the call to sortTable.
07:39Don't pay too much attention to the logic of how the sorting works. We'll cover
07:43that later. Right now we are just trying to get these links off of this item here.
07:47So we are going to copy that out and then I'm going to put in an anonymous
07:52function in line and I'm just going to paste that in there. Now I'm going to do
07:58that for each one of these guys. So I did it for the ItemDescend. This is going
08:02to be ItemAscend, this is going to be PriceDescend, and this is going to be PriceAscend.
08:16And the only difference between each of these guys if I remember correctly is
08:30the column being sorted and whether it's ascending or descending, that's what
08:33these two parameters mean right here. So I just need to change that guy to false [00:08:41.5 5] and these still work on the price column, and I need to change that guy to false.
08:50Okay, so now we have a function that on the fly is going to operate on the
08:56sortControls. So we can go ahead and take off this function called, and just
09:03make it a hash mark for now. Copy this guy off as well, copy this guy off and
09:11get rid of this one as well.
09:14Okay, so now we have removed the JavaScript from being inline on the element.
09:18So now what we need to do is call the insert sortControls function when the
09:23window loads. So we are going to do that down here, we are going to say
09:26addEventHandler on the window when it loads, and we are going to call insert
09:34sortControls and we are going to pass false as the capture.
09:39So now let's go back and look at our code in action. We are going to bring this
09:44up in the browser. So you can see that now when I'm mousing over, there is no
09:49more status line indicator that this is a JavaScript function. So when I click,
09:54it still sorts. So that's good.
09:57Now we still haven't entirely solved the problem of what happens when script is
10:01turned off or not available. So let's go back and fix that problem. So we are
10:05going to go back to the code and we are going to remove the line that says
10:11remove the href attribute.
10:15That was what was preventing the status bar from showing anything. Let's go
10:19back to the code now and for the ItemDescend, now ordinarily what you'd have in
10:26the case for progressive enhancement, especially when script is unavailable.
10:30You'd probably want to have some sorting function available to the user on the
10:34server side. So you'd have something that looked like this, like sortTable. --
10:40I don't know, maybe it's ASP whatever service site you are using and then
10:44you'll have some argument like column equals whatever and direction -- in this
10:53case I think it was descending. This is what your links would look like. So I'm
10:57just going to copy this on to each one of these guys and this is going to be
11:06columns 1, and this guy is ascending and this guy is ascending. Okay, so now
11:14let's save this and we are going to back into the browser.
11:19Now you can see that as I mouse over what's happening is the hrefs are still
11:24there and when I click, now it's sorted, but we had a problem because I didn't
11:30actually define the file for that. So let's go back and fix that problem.
11:35And we are going to fix that problem by going back to the JavaScript. And in the
11:39case for JavaScript we are going to go back and add in that remove attribute.
11:45We are going to say oLink. removeAttribute. I took it off voluntarily, so you
11:50could see what would the mouse over behavior be, but we are going to go ahead
11:54and remove the href attribute again. And this is going to prevent that click
11:58problem. And we are going to do it there, and we are going to do it there, and
12:03we are going to do it there.
12:04Okay, so now one more time let's go look in the browser. So now you can see
12:11that when we load and JavaScript is enabled, the href attribute is gone, right?
12:16It's not showing up in the status bar anymore and linking work.
12:20Now let's watch what happens when I turn script off, and I'm going to refresh
12:24the page. Now that JavaScript is off, you can see that the mouse over behavior
12:29has returned for the hrefs. Now I haven't defined the server side scripting
12:32logic, but you get the idea. The idea is if somebody came to this page and
12:35scripting was off, they would get the server side behavior or if say the DOM
12:40wasn't available, we would add a check for that. But if scripting was enabled,
12:45refresh the page, now they get the nice progressively enhanced behavior.
12:51And just to prove to you that it works cross browser, let's go ahead and browse
12:55this in Firefox.
12:59So here you are and see we are sorting with JavaScript, there is no links
13:05there. If I disabled JavaScript and we refresh, you can see that what we are
13:13doing now is you see we are getting the rollover behavior with the links.
13:17And if I were to go ahead and build those server side pages to do the sorting,
13:21the user would get the default server behavior for sorting, but now that we
13:26have got JavaScript enabled, we don't have to worry about that.
13:30So that's an example of how you can use progressive enhancement in your web
13:35pages to enable features unobtrusively and only if specific features are available.
Collapse this transcript
5. Object-Oriented JavaScript
Understanding objects
00:00Object-orientated programming is a very powerful feature of modern versions of
00:05JavaScript and it's something that you should really learn how to do in order
00:09to become a much more effective JavaScript programmer.
00:13Using object-oriented programming you can create objects that are portable and
00:18reusable and can be used across multiple projects, given to other developers,
00:24merged into modules and libraries and actually reduce your overall coding
00:30effort by taking advantage of something we call inheritance which I'll look at
00:33shortly. So let's get started looking at object oriented JavaScript.
00:38Let's begin by looking what objects are. Now you are probably familiar with
00:42some JavaScript objects, because JavaScript provides some built-in ones.
00:48You have probably seen syntax like new String or new Date or things like that.
00:54In addition to using the built-in objects JavaScript allows you to create your
00:59own and this promotes code reuse and modularity as I said earlier. Now objects
01:05can either be stand alone with their own set of properties and functions or
01:10they can inherit properties from other objects, and we'll see that a little bit
01:14later, but it's very powerful.
01:15To declare your own object, you write a function and in object oriented
01:19terminology that's called a constructor function and when you write this
01:23function, you then call it using the New keyword and that creates your new object.
01:27If you want to extend the properties of other objects, you use what's known as
01:33the Prototype property and again we'll get into this in a moment, but the idea
01:37here is you use the Prototype property on objects to define functions and other
01:43properties that get created automatically for you when you instantiate to use
01:48another object orientated term, a new object of a certain type.
01:53So to declare an object you write a function with the same name as the object.
01:58You can see in the example here, I have got function Rectangle() with a couple
02:03of braces. Now this is an empty object, it's got nothing in it. To create a new
02:08instance of that object you use the New keyword along with the object name and
02:13you either assign it to a variable or you don't have to, but the whole idea
02:17here is you say New and then object type and that makes a new instance of your object.
02:22So here you can see I have got some code. It says new Rectangle and it assigns
02:26the rectangle I just created to the variable myRect. Now this is all fine and
02:30good, but not a particularly useful object because it doesn't have any
02:34properties or functions on it. So we have to fix that. And by the way methods,
02:39that's just an object oriented term for functions that are part of an object.
02:44So Properties and Methods are defined when the object is created using the
02:48'this' keyword. So you can see in the example there I have got my rectangle
02:52function only now I have modified it slightly. It now takes two arguments a w
02:57and an h and that's width and height. And inside the rectangle's constructor I
03:02use a syntax this.width = w. So while this rectangle is being constructed the
03:08'this' keyword means this object. So I'm on the fly creating a property named
03:13width and a property named height and I'm assigning those, the values of the
03:16width and height that the caller passed in.
03:19Now I can also do this for functions, but that's a little bit silly and the
03:23reason is because properties are typically associated with a given object. So
03:29each rectangle is probably going to have different width and different height
03:31and that's why you define them in a constructor like this. But every rectangle
03:35is going to have more or less functions that you declare for it.
03:38So we use a slightly different syntax to declare the methods for the rectangle
03:43and that's using the Prototype object. So the way you do this is you type
03:48Rectangle.prototype and then the name of the function you want and I'm using an
03:54anonymous function here that basically calculates, in this case, area of the
03:58rectangle and inside this function I can again use the this keyword to refer to
04:04the current object that's being operated on.
04:06So here I have got an area function and it returns width times height and it
04:10calculates the area and I have got another one here called perimeter and that's
04:14a function that simply adds up the width and height and that gives you the
04:18perimeter, the distance around the edges of the rectangle.
04:23So now when someone says new rectangle and they pass in two numbers here, the
04:28width and height properties are assigned the values that were passed in and
04:33these two functions are automatically created on my rectangle object.
04:37Now in addition to properties and methods that are on each instance of the
04:43object, you can also create what are known as class level properties and
04:47methods and these are not associated with any specific instance. So let's take
04:54a look at an example.
04:55I might define a property named empty on my rectangle object and just create a
05:01new default Rectangle (0,0) and this allows me to have a more compact syntax in
05:08the future, if I want to, say compare a rectangle to the empty rectangle to see
05:13if it is empty. Similarly, I might define a class level function for the
05:18rectangle object named Max and that takes in two rectangles and just figures
05:23out which one's area is bigger and returns the rectangle that happens to have
05:27the larger area.
05:29Now I wouldn't call these functions as a result of any instance. So if you go
05:33back to my example earlier where I had myRect = new Rectangle to call the
05:37functions like area and perimeter, I would then say myRect.area. Now in the
05:43case of the class level function I would call it using the class name and then
05:48the name of the function. So I would say for example Rectangle.Max and then
05:53pass in myRect and my other myRect and that would then figure out which one of
05:59those is larger.
06:00Okay, I think we have reached the point now where we know enough where we can
06:03define our own object. So let's switch over to the code and see how that works.
06:08So I have my code entered up here and what I'm going to do is in the Script
06:12block here, I'm going to hit Return and I'm going to declare my Rectangle
06:17class. So I'm going to type function Rectangle and I'm going to give it a width
06:26and a height like we saw in the example with slides.
06:29So now I have my constructor for my rectangle and just as I did earlier I'm
06:34going to assign two properties. It's going to be this.width = w and
06:39this.height = h. Okay, so now I have got my rectangle's constructor declared
06:47and I could just stop here. I could just simply call it a day and have my
06:51rectangle object, but again it doesn't really do very much. So we've got to add
06:54some functionality.
06:56So now outside the constructor I'm going to type a Rectangle.prototype.area =
07:07function() and this function is going to return this.width * this.height.
07:23And I'm also going to declare my perimeter, Rectangle.prototype.perimeter =
07:31function(), and I'm going to return 2 * this.width + 2 * this.height.
07:52Now I've got my fully defined class. I've got some properties, I've got some methods.
07:56So now we can do something like test it out and say alert and we'll
08:03come back to that say var myRect = new. The tool that I'm using is Visual Web
08:11Developer 2008 Express and it's smart enough to realize I have defined a new
08:17object called Rectangle. Now whether or not your tool does this, this is nice
08:20little convenience feature, but I'm just going to go ahead and say new
08:23Rectangle and it knows it takes the width and height. So I'll give it 5 and 6
08:29and we'll alert(myRect.area()) and let's try browsing this and see what happens.
08:42I'm going to browse it in the browser and you can see that the area is 30.
08:47So we created the new Rectangle and we defined some properties and some
08:50functions and we tested it out by instantiating a new rectangle object and
08:56calling the area function.
08:59So that's pretty much all you need to know to define your own object and add
09:05some properties and functions to it. In the next example we'll see how we can
09:10define some other common object properties in order to extend this object's functionality.
Collapse this transcript
Defining common object methods
00:00In the last section we saw how to define our own object type of rectangle and
00:05add properties and methods to it and in this section we are going to take a
00:09look sat ways of defining some common object methods that JavaScript provides
00:15for its own built-in ones. The reason you want to do this is because you want
00:19to provide the same kind of features for your objects that JavaScript provides
00:24for the ones that are built-in so that as you are using these objects or maybe
00:28other people are using them, they can call some fairly common methods that
00:33exist on the built-in JavaScript object types. So let's take a look at these.
00:37The first one is the toString method and the toString method is called on an
00:41object and it's really simple. It just returns a string representation of the
00:46object that it's called on. The default return for this, you can see there, is
00:51object and then the name of the object's class inside two brackets. So if you
00:57were to call a toString function on a variable of type just object, if you said
01:02var obj = new Object then the result you would get back from toString would be object.
01:09Now we are going to change the behavior for the rectangle that we just created.
01:13So here if I have typed out Rectangle.prototype. So this is the same as
01:17declaring the methods as in the previous example and here I'm saying that the
01:23toString method is equal to a function I'm about to write. Now don't worry
01:27about the fact that the toString method already exists on the object's base class,
01:32because I'll get to that in a moment, but just follow along with me.
01:35So the function that we are writing is going to return the string "Rectangle of width:"
01:40+ this object's width, then the string "& height" andthe rectangle's height on the end of it.
01:48So you're probably wondering why we are defining a function that already exists on the
01:53object's base class? Well, the reason we are doing that, this is called
01:56overriding a method. What we are doing is we are saying hey, a rectangle object
02:00don't worry about the previous implementation of the toString method that
02:04exists on your Object base class. We are going to replace it with this one and
02:10it's going to have our own functionality that we are defining right here.
02:13This is one of the very powerful pieces of Object-oriented programming and I'll
02:18explain it a little bit more in depth later on when we cover object inheritance.
02:22Another common method is the valueOf method and valueOf returns a
02:27primitive value that JavaScript uses when you compare two things together in a
02:34numerical comparison like greater than or less than or that kind of stuff.
02:37Now not every object can obviously return a valueOf result, because not every
02:43object has a corresponding primitive type and rectangles don't necessarily have
02:49a corresponding primitive type like an integer, but I'm contriving an example
02:53here just to show you how it works. So let's imagine that we wanted to have the
02:56valueOf function return say the size of the rectangle's area. What we are doing
03:01here is defining Rectangle. prototype and then valueOf and the anonymous
03:05function that returns just whatever the rectangle's area is. Again these are
03:09two methods that exist on every JavaScript object and we are defining our own
03:15versions that fit the purpose of our rectangle object.
03:19There are a couple of more we should look at. You should consider writing an
03:22equals method to compare an object of one of the types that you have defined to
03:29another of the same type, and again the reason you want to do this you have to
03:33remember JavaScript doesn't compare objects to each other using the equals
03:38operator like it compares numbers or strings. All it does is compares the two
03:43object references to see if they are both referring to the same object. If you
03:48actually want to see if one object has the same properties as another you
03:53should follow this kind of convention and then write an equals method to
03:58compare them together.
03:59So here I'm writing the Rectangle. prototype.equals function and that takes a
04:05rectangle as its argument because it's going to be compared to the this object.
04:10And we simply say hey, if this rectangle's width is the same as the width of
04:14the rectangle that was passed in and the height is the same, well, then they
04:18must be equal to each other.
04:20And then there is another useful method to write which is called compareTo and
04:24this can be used when sorting objects such as using the array's sort function.
04:30This function returns less than 0 if the compared object is larger, greater
04:35than 0 if the compared object is smaller and 0 if they are same.
04:40So in our example, imagine again we want to compare two rectangles to see which
04:44one is larger and which one is smaller by comparing their areas. So inside the
04:49compareTo function we return whether this rectangle's area minus the given
04:56comparable rectangle's area is larger or smaller. So when we subtract these two
05:00numbers if the area that we are comparing to is smaller then this, the function
05:05will return a number larger than 0. Otherwise, if this object is smaller than
05:10the one we are comparing to, it will return a number less than 0 and if they
05:13are the same, it will just return 0.
05:15You can also determine at runtime what type an object is and you do this by
05:22using what's known as the instanceof operator. So to see if an object is an
05:27instance of a specific type you use the intanceof operator like this.
05:31You say myObject instanceof myClass. Take an example. We'll say myRect instanceof
05:39Rectangle. Well, that's true right. When you say myRect = new Rectangle,
05:44you are creating an object of a class that's Rectangle.
05:47We can also say myRect instanceof Object, that's also true. Because when you
05:51define a new object using the constructor function like we showed earlier on,
05:55all of those objects implicitly inherit their properties from the Object base
06:01class that's built into JavaScript. If we said myRect instanceof array, well,
06:06that would return false, because rectangles are not instances of arrays.
06:11Okay, so now that we have seen how to define some common object functions and
06:15determined what their types are, we know enough to go back and enhance our
06:18rectangle class. So let's jump over to the code to do that. So we are back in
06:23the code now and here is my Rectangle class and I'm going to enhance it with
06:28some of the stuff that we just learned. So I'm going to say
06:30Rectangle.prototype.toString and that's a function and it's going to return
06:45"Rectangle of width:" + this.width + "& height:"+ this.height. Okay, that's the
07:07toString function. I'll say Rectangle. prototype.valueOf and that's a function
07:22and we are going to return this.area.
07:29Now we have got those two defined. We are also going to define the equals
07:33function, Rectangle.prototype.equals, and that's going to take a Rectangle object.
07:45And we are going to return this. width == oRect.width and this.height ==
08:00oRect.height. Alternatively, we could also just compare the areas and see if
08:10the areas are the same, but I'm choosing to compare them using this method.
08:14We have to write now Rectangle.prototype .compareTo. That also takes a rectangle
08:27argument and we are going to return this.area - oRect.area. So now that
08:42we have defined these functions, we can start playing around a little bit to see
08:47what happens when we define some rectangles and do some comparisons.
08:52So we have got one rectangle of width 5 and height 6, let's define a few more.
08:56I'll say myRect2 = new Rectangle and this will be 7 and 8 and what else?
09:06We'll do var myRect3 and we'll make a new Rectangle and we'll give that one the same
09:17dimensions as myRect. Finally, we'll say var myRect4 = myRect.
09:26So we have defined four rectangles now and let's take a look at what happens
09:30when we call some of the different functions that we just defined. So let's say
09:36we are going to call the toString one first. So let's alert(myRect.toString())
09:46and then after that we'll say hey, let's alert(myRect instanceof Rectangle) and
09:57see what that comes back with and okay let's browse that and see what happens.
10:02So we'll bring up the browser, and oh! It looks like I forgot a semicolon.
10:09Let me go back and fix that really quick. Actually, I have got to put in the
10:16function constructor. Okay here we go, oh! It did it twice. Now we are ready to
10:26browse. So you can see in the first example when we call toString we have a
10:32rectangle of width 5 and height 6. So that's the result of the toString
10:37function being called. You can also see that we called the instanceof function
10:42and that came back, yes, myRect is an instance of Rectangle. Okay.
10:47Now let's see if our comparison functions are working. Let's write a function,
10:53which says alert myRect.equals. And we are going to compare it to
11:02myRect2 and we are going to do the same thing for alert(myRect.equals.(myRect3)) and then
11:20finally we'll alert(myRect.equals.(myRect4)).
11:33Let's have a look now what happens. I'm going to browse. So the first thing
11:39that you can see is we called the equals function on a rectangle that's not the
11:42same. That's alerting false then we compared myRect with the rectangle that had
11:48the same dimensions that came back as true. And the last line that said, hey,
11:53are myRect and myRect4 the same? Yes, that also came back as true.
11:58I will give you an example of what it's like to define new objects and add some
12:05properties and in this case we overrode some of the functions that were in the
12:09base class object. So at this point we are now ready to move on and look at how
12:15we can inherit properties on one object from another object.
Collapse this transcript
Using object inheritance
00:00In the preceding examples, we have looked at how you can define your own
00:04objects in JavaScript and add methods, and functions and override some of the
00:10properties and functions that are in the base class of JavaScript objects.
00:15In this example, we are going to take a look at how you can define your own
00:19JavaScript objects and have them inherit properties of other objects that
00:23you've defined.
00:25Objects in JavaScript can inherit properties and methods from another object,
00:29and this is really one of the most powerful features of object-oriented
00:33programming. The reason of this is because it allows you to define objects that
00:38differ just so slightly in how they work, but have a lot of common
00:43functionality. So you can group that common functionality into base-level
00:47classes and then customize the higher-level classes for whatever the particular purpose is.
00:54To get a graphical representation of how this looks, let's take a look at a
00:58diagram. So in the preceding example, we defined our new object of type
01:03Rectangle, and that inherited its properties from what we call the base class;
01:08the class named Object which is at the base-level of every object in JavaScript.
01:14We then defined a class called Rectangle, which in object-oriented terminology
01:19is a Subclass of Object, and the Object is a Superclass of Rectangle. We then
01:27defined these width, height, and area properties on the Rectangle object.
01:34What we are going to do now is define a DepthRectangle and we are going to make
01:40this a Subclass of the Rectangle object that we just defined. And we are going
01:46to add a couple of new properties depth and volume. So you can think of
01:51rectangle as being a two-dimensional rectangle. DepthRectangle is going to be
01:56like a cardboard box. It's going to have a width and a height. It's also going
01:59to have a depth to it.
02:01Now, you might want to ask yourself before we begin why would I do this?
02:05It seems kind of silly that we have to define the DepthRectangle class all over
02:10again with width and height and area and all that stuff. But really all we want
02:15to do is just add the ability to have some depth to it. We want to take
02:19advantage of all that functionality that we've already got in the Rectangle
02:23class, then just add it to the DepthRectangle class.
02:27To do this, step one is we are going to write the constructor function for the
02:32DepthRectangle subclass, just like we did for the Rectangle. The only
02:37difference is we are going to call the constructor for the Rectangle inside the
02:43constructor for our DepthRectangle. So you can see what I've written here is
02:47function DepthRectangle and it takes the same arguments as my Rectangle
02:53constructor did. But I have added a little d on the end here for depth.
02:57Inside of the constructor for DepthRectangle, I have got Rectangle.call and I'm
03:03passing in the reference to this object with width and height. Now, you might
03:08be wondering where this came from. Every function in JavaScript has a call
03:14function associated with it. And it's basically a pretty verbose way of
03:20invoking that function on an object as if you were calling it as a method of that object.
03:26The reason we need to do this is because we want the Rectangle's base class
03:31constructor to set the width and height properties from w and h, just like we
03:36did in the previous example. And we don't want to have to duplicate all that
03:39code in the DepthRectangle class, so we just tell the Rectangle class, hey, go
03:44ahead and call your instructor, and here is the properties that you need.
03:47And then in my constructor, I'm going to save a side the depth value from d so I
03:53can use it in my subclass.
03:55Okay, now that we have written a constructor, we have to set the prototype
03:58object of our DepthRectangle to be a rectangle. Otherwise we would just get a
04:04subclass of the Object base class and that's not what we want. So you do that
04:10by writing DepthRectangle. prototype = new Rectangle.
04:14So now the DepthRectangle's prototype object is set to its superclass, which is
04:19Rectangle, and that's going to allow us to inherit all of the functions that
04:24are on the Rectangle prototype. Okay, so far we've defined the Rectangle's, the
04:28DepthRectangle's constructor and we've told the DepthRectangle "hey, you are
04:33based on the Rectangle class."
04:35Now since the DepthRectangle prototype was just created with the Rectangle's
04:38constructor function, we have to reassign the constructor property to be our
04:45DepthRectangle. And here is why we need to do that.
04:48In the previous example we said DepthRectangle.prototype = new Rectangle.
04:52There is a property called constructor that is on every prototype object and it
04:57refers to the constructor that was used to build the object, because we said
05:02new rectangle in the previous line of code, the DepthRectangle's prototypes
05:06constructor property is now set to Rectangle. We can't have that. We have got a
05:09point it to our DepthRectangle instead. So that's what this line of code right here does.
05:13Okay, so now that the DepthRectangle prototype is all setup properly as
05:18pointing to the right kind of object, we can go ahead and start adding methods
05:23and properties to our DepthRectangle class, just like we would the Rectangle
05:29class we did in the previous example. So now, I can say DepthRectangle
05:33prototype volume is equal to a function that returns the Rectangle's area times
05:40the Rectangle's depth.
05:42Again, here you are seeing an example of overwriting a function. This area and
05:47this depth that's what comes back from the volume. In the case of
05:50DepthRectangle's prototype to string function, we want to send back a string
05:55that takes into account not just the width and the height, but also the depth.
06:00So here is where we are doing that, we are returning the string that we build up that way.
06:05So I think we are at a point now where we can jump back over to the code and
06:10take a look at how we would build this DepthRectangle example using the
06:13Rectangle class that we had from the previous section.
06:17Okay, so here I'm back in the code and here is the Rectangle class that I
06:22declared in the previous example. So now, we are going to build our
06:27DepthRectangle on top of this one. So I'm going to say function DepthRectangle
06:35and that's going to take a width, a height, and a depth. And I'm going to call
06:43Rectangle.call (this w, h); and then this.depth = d, and I'm done.
07:00So now I've got the constructor all written. Now, I'm going to say
07:03DepthRectangle.prototype = new Rectangle and I'm going to say
07:15DepthRectangle.prototype.constructor = DepthRectangle();. Okay, so now I have
07:25squared up the objects, everybody knows and who everybody else is.
07:29Now I'm going to define my own functions. DepthRectangle.prototype.volume =
07:40function(), and I'm going to take advantage of the existing this.area, return,
07:55to this.depth, and DepthRectangle.prototype.toString
08:06and return "DepthRectangle of width: + this.width + " & height: + this.height +
08:38" & depth: " + this.depth. And that should be good to go.
08:50Now, we can start creating some new instances of our new rectangles and see
08:56what happens. So let's say var myRect = new Rectangle,
09:02and say var myDepthRect = new DepthRectangle. So let's see what happens when we check to
09:20see if myRect is an instanceof DepthRectangle.
09:29Now I'm going to browse this in the browser. Go up here and -- now this will be
09:32different in your tool. I've been doing this with my little keyboard shortcut,
09:36but you can view in the browser depending on whatever editor you are using.
09:40I'm just going to choose the View in Browser here in Visual Web Developer.
09:44That's going to bring up the browser. You can see that the result here is false.
09:48That's because myRect is a Rectangle. It's not a DepthRectangle.
09:53Now myDepthRect you would expect this to be true. But let's see what happens if
09:58we say it's an instance of rectangle. Oh, that's true. And the reason that's
10:04true is because DepthRectangle is a Subclass of Rectangle. So yes,
10:10a DepthRectangle is a Rectangle, but a Rectangle is not a DepthRectangle.
10:15Now let's see what happens when we say myDepthRect.toString. I'm going to view
10:24this in the browser and you can see now that the string that gets returned from
10:29two strings is different for DepthRectangles than it is for regular Rectangles.
10:33This one says DepthRectangle of width 5 & height 6 & depth 7, whereas if we
10:39were to add a function just for the Rect -- let's do that right here. Now let's
10:47try that again, you can see that for regular rectangles it looks like this and
10:52for DepthRectangles it looks like that.
10:53So the two strings are now different based on what kind of class they are.
10:57Hopefully, this has given you some insight into how you can define classes and
11:02subclasses inside JavaScript. And in the next section, we are going to take a
11:07look at how we can work with objects to extend the properties of the built-in
11:14JavaScript objects.
Collapse this transcript
Extending built-in types
00:00So far we've focused only on building your own objects, but you can actually
00:04extend the functionality of the built -in JavaScript types as well. So for
00:09example, you can add your own properties and methods to the objects that
00:15JavaScript gives you.
00:16So an example of this might be extending the array object to provide a new
00:22function called longestElement. Imagine you had an array like you see down here
00:28at the bottom of the example, and I have got variables as testArray = new
00:33Array, and I have got some numbers and some strings and I threw in a Date
00:37object just to mix things up. Suppose I wanted to have a function that told me
00:44which one of the elements in the array was the longest in terms of number of
00:50characters. Well, that function doesn't exist today.
00:53If I were to call this function without having defined it, I would get a
00:58JavaScript error. Well, that's okay. We can just simply make our own. And the
01:02way that we do that is the code up here. So just as I defined methods on the
01:08prototype of the objects that I built for myself, I can also extend the methods
01:14and properties on the prototypes of other objects, say the array for example.
01:19So in this example, I'm saying Array. prototype.longestElement = and I'm making
01:24a new function here. So I'm defining a new function right on the
01:27Array.prototype itself. I have got a variable maxLength and I set it to 0, and
01:32then I have a loop. And the loop basically loops over all of the contents of
01:37the array converted to a string, and sees if the length of that string is
01:42longer than the longest one I found so far. And if it is, I record it as being
01:47the longest, and then when the loop is over, I return the length of the
01:52longestElement.
01:53Since this example is basically building on the same principles we learned in
01:57the previous examples, we can just jump over to the code and see if we can
02:01write this function and extend the array class to provide a new method for us.
02:05Okay, so here I'm in the code. And what I'm going to do, you can see I have got
02:09my array here and I have added a really big long string at the end there. And I
02:15have my alert and it alerts the testArray.longestElement function
02:21and shows the result.
02:23Well, let's try to browse this and see what happens. Again, an Error, and the
02:30Error is yeah you can see, Object doesn't support this property or method, and
02:34that's because the array class doesn't have a longestElement function built-in.
02:41So we are going to go ahead and fix that. We are going to say
02:44Array.prototype.longestElement = function(). I'm going to say var maxLength = 0.
03:05And I'm going to say for (var i = 0; i < this.length).
03:16And remember, since we are extending the array's prototype, the this keyword will
03:20refer to whatever array object that we are working on. So I'm going to loop
03:25over all the array elements. I'm going to say if this sub i .toString().length >
03:41maxLength so far. I'm going to assign maxLength = equal to this right here.
03:54Copy, paste that, and then finally I'm going to return maxLength.
04:01What we've done is we have added our own custom function to the array's
04:05prototype. So we've in effect extended the array class to meet some need that
04:11we had. So now, let's go back and look at this in the browser. Now you can see
04:17that the result comes back, we don't get an error anymore because we've defined
04:20the function now, and you can see that the longestElement is 75 characters long.
04:24So let's go back in here and take out this really big long string I added, and
04:31just leave the numbers and strings and dates, let me take off that spare comma.
04:38Go back, run this in the browser, and now the longestElement is 27 characters
04:43and that's probably the date object because we converted date to a string.
04:46It gives you this big long universal date string thing. Just to make sure that
04:51this is working cross browser, let's browse this in Firefox and same result.
04:58Well, the number was different. If you notice, it was 27 in my example and 57
05:03here. The reason for that is because the date format is probably different. So
05:07let's just see if that's the case. And browse this with browser and you can see
05:18that this is the date that Internet Explorer comes back with, and go to
05:25Firefox. Yeah, you can see that they actually have a much larger string because
05:32they put the time zone on the end, and it's more characters.
05:36So what we've done here is we've extended the array class with a custom
05:41function. Now you might be asking yourself, is this a good idea, should I go
05:45doing this, should I go extending the built-in JavaScript classes in? You could
05:48make a strong argument that if you are going to do this, then give out your
05:52code. Other JavaScript developers might be confused or whatever, if they see a
05:57function that you've added to a base class, they don't know how it's there and
06:01they have to go looking through your code.
06:02I would say you should only do this if you are building a JavaScript library
06:07that you intend to be used by other JavaScript developers, and you are going to
06:11document the fact that you have extended the base classes like this, or if you
06:16are using this script either in-house or in your own projects, and you group
06:21all of these extensions that you make together in a single module or a
06:27collection of extension modules, just so you can keep better track of the fact
06:32that you have done this.
06:33You don't want to go losing this code. Otherwise all the code that you write
06:36that depends on it, you are going to have to either go back and reconstruct it
06:39all or figure out how it works. So take care when you do this, but it's a
06:44really powerful way of extending the functionality of the built-in JavaScript object types.
06:49In the next example, we are going to see how to take this kind of concept and
06:54expand it to build what are known as wrapper objects and that's the subject of
06:58our next example.
Collapse this transcript
Using wrapper objects
00:00There is a pretty fairly common use of object oriented programming in
00:03JavaScript and that is to create what are known as wrapper objects.
00:07Wrapper objects are used to, as their name implies, wrap the functionality of
00:13some of the common features you find in JavaScript and HTML. Some examples of
00:18this are controls like select lists, or forms, or buttons, or text fields, Ajax
00:24features like the XMLHttpRequest object or other content and things you will
00:31find in your pages.
00:33The reason why you use this technique is to simplify working with features that
00:37are complex, or add new features to existing browser objects, or maybe change
00:44the way that some features work in the browser.
00:48What we are going to do is in this example build a wrapper object that wraps
00:54the functionality of the well-known select list in HTML. We are going to use
01:00that to add some of our own features to it and make it easier to work with. So
01:05let's jump over to the code and see how that works.
01:08What I have got here is a form on the design surface. This is a select list
01:15right here. I have got a couple of buttons and I have labeled them Fill The
01:19List and Clear The List. Basically, different controls to test out the
01:23functionality of the list that I have built right here. So let me jump over to the code.
01:29So here is the code and you can see here is the form with a select list in it.
01:33Right now, it's empty. It's got an id associated with it and here are all the
01:38buttons. So what we are going to do is build an object that wraps the select
01:44list and provides some convenience functions for working with the select list.
01:51So what I'm going to start off doing is creating a constructor called function,
01:56I'm going to call mine BetterSelect because it's going to be better. It's going
02:04to take a select list as its argument. In the constructor, I'm going to say
02:12this.objSelectList = oSelList. Let's leave that there for now.
02:23Okay, now that I have defined the wrapper object; By the way, I could go ahead
02:28and add some more properties but this is good for now. What I'm going to do now
02:31is define some functions that provide some convenience for me when working with select lists.
02:37So I'm going to say BetterSelect. prototype.clear = function(). This function is
02:49going to clear the contents of the list. So we'll say
02:52this.objSelectList.options.length = 0. So that's going to clear out the contents.
03:05We are going to write a function called BetterSelect.prototype.fill
03:14and that's going to take a function that gets an array of values to fill the list with.
03:24What we are going to do is when we fill the list, first we are going to clear it.
03:27So we'll say this.clear(). Then we are going to say for, have a little loop.
03:34I'm going to loop over all the elements in the array.
03:45Then inside the loop, we are going to go ahead and add some new options to the list.
03:53So this.objSelectList.options, sub i, = new Option(). An option is a built-in
04:07JavaScript object. We are going to pass in aValues, sub i, as the text to use.
04:17Let's add one more. BetterSelect. prototype.getCount and that's a function.
04:27That's just going to return this.objSelectList.options.length.
04:39So now we can go ahead and start hooking up some of these functions to our form
04:44controls. Obviously, before we can use any of these functions, we have to
04:49create the BetterSelect object.
04:51So what we are going to do here is create a global variable called
04:55var mySelectList and that's going to be null. Then in window.onload, we are going
05:06to run a function that creates that. mySelectList = new BetterSelect.
05:17Now I need to get the reference to the select list that I have already got in
05:22my document and that's this guy right here. So I'm going to say
05:26document.getElementById and you can see it's called theList. So that
05:36creates a new BetterSelect object which wraps this select object right here.
05:45Now that I have created the new BetterSelect list, I can write some functions
05:49that will fill them and do other operations. So I'll have a function called
05:53fillList(). And fillList() will basically say mySelectList.fill and I'll pass an array.
06:08In the array, I'll have some strings, "one", "two", "three", "four", "five".
06:24Let me go and hook up some of these events now. So for Fill The List,
06:31I'll say onclick = "fillList()". For clearing the list, that will be onclick =
06:44"mySelectList.clear()". On What's The Count? I believe we wrote a function
06:58for that one. Yes, we did. Say onclick = "alert(mySelectList.getCount())".
07:21Well, I think we are at a point now where we should just try to run this in the
07:24browser and see what happens. So let's bring this up in the browser. So we are
07:30going to click on What's The Count? Right now, the count is 0. So I'm going to
07:34click on Fill The List. You can see when I click Fill The List, the list gets
07:37filled with stuff. When I Clear The List, the list gets cleared. So I can fill
07:42and clear. Now when I click What's The Count?, the number is 5. Just to show
07:46you that it's cross-browser, let's browse in Firefox, same idea. Okay,
07:55everything is working.
07:56So what we have done is we've created an object that takes a page object in the
08:03HTML and wraps it with some additional functionality that we've built. Now some
08:09of the functionality is built on things that are not very complicated, like so
08:13for example, clearing the list. You just set the options array's length to be
08:170, but you can imagine that if we enhance the functionality of this select list
08:21even more, then maybe clearing the list might mean more than just doing
08:24something like this.
08:25So we've wrapped the object with some functions that have abstracted away the
08:30functionality, made it easier to use and made it more extensible. Let's get a
08:35little bit more fancy. One of the things I've always really disliked about the
08:40built-in SelectObject that's in HTML is that it doesn't give you a good way of
08:45finding content that's in the select list. So I really wish that I had a
08:50function that I can just call that finds content for me.
08:55So here is what I'm going to do. I'm going to say BetterSelect.prototype.find =
09:04function() and we are going to say there is a strToFind and a Boolean variable
09:13that says whether it should be selected when it's found.
09:20So now what I'm going to do is write the code for this one. I'll say var indx = -1.
09:28So we are going to initialize the index of the item that gets
09:30found to be -1. So that way if the function returns -1, we'll know that
09:35whatever we were trying to find couldn't be found.
09:37Then I'll say this.objSelectList.options .selectedIndex = -1. So we are going to
09:53de-select anything that's already selected in the list. Now we are going to
09:58write a loop that loops over all the contents of the array, the options in the
10:07select list. I'll reuse the getCount function for that.
10:17So now I'm going to look for all of these guys and say if
10:20this.objSelectList.options, sub i, .text == strToFind, then I'm going to set
10:40the index to be the item that we found. If we wanted it to be selected, we are
10:52going to set this.objSelectList. options.selectedIndex to be that.
11:06Now we just have to hook up the event. So down here in the code, you can see I
11:14have a text field. The text field is the txtToFind and there is button next to
11:21it that says Search. So what I need to do now is hook up the event handler for
11:26the button to search the list for the content that we are trying to find.
11:31Let's do that. First, I'm going to write a function called findIt(). findIt() is
11:41going to call the mySelectList.find() function and we'll say true, we want it to
11:51be selected. We are going to pass in the string that's in the text field there.
11:56So I'll say document.getElementById. What is the ID on that guy? It is
12:03txtToFind. So now let's try out our enhanced select list and see how that works.
12:15So we are going to fill the list with some content and there are 5 items in there.
12:19So now we are going to try searching. Let's try searching for six. Yeah,
12:23that didn't find anything. Let's try searching for three. Now that apparently
12:29didn't work. Let's see, oh! I messed up the findIt function. So now I have to put
12:38in the onclick handler here, onclick = "findIt()".
12:45So we also need to look for the value of that text field. So I have our onclick
12:57and findIt(). findIt() is going to call mySelectList.find and it should find
13:05the string. Let's fill it. Try and look for three, and there it is. You can see
13:13it found it and selected it. Let's try looking for one. Yup, that worked.
13:18Let's try looking for six, not in the list. Let's take a look at that in the other
13:23browser just to make sure it works cross-browsers. Go on Firefox, let's look
13:31for one, very good. Let's look for six, okay.
13:36So you can see that what we have done here is we've taken an existing HTML
13:41object and we have created our own JavaScript object whose sole purpose of life
13:46is to basically provide better, friendlier APIs and enhanced functionality than
13:51you would get on the base object itself.
13:53You can do this with any HTML object, any one of the built-in JavaScript
13:58objects. You can create these wrapper classes that extend and enhance the
14:03functionality to make your coding a lot easier, more productive and maintainable.
Collapse this transcript
6. Using Regular Expressions
Understanding regular expressions
00:00Regular expressions are probably one of the most powerful text processing
00:04features of JavaScript. That's the subject of this particular chapter.
00:10Regular expressions have been around for a while. If you've ever used a
00:13programming language like PEARL or some others, you have probably come across
00:17regular expressions, but let's start at the beginning and talk about what
00:21regular expressions are.
00:22Essentially, regular expression is an object that describes a pattern of text
00:28characters. You can see some common patterns here. For example, there is U.S.
00:34postal codes, which are five digits followed by an optional dash and four more
00:40digits, which is supposed to help the post office to get mail to my place faster,
00:45which I'm not sure if it ever actually works.
00:47There are email addresses of the form of a bunch of characters followed by an @ sign,
00:53followed by some more characters, followed by something, .com/.net,
00:59something like that. Another common pattern is ISPN numbers. These are used in
01:03the publishing industry to identify books and where the book came from and that
01:07kind of stuff. ISBN numbers have this pattern here.
01:10So patterns are pretty common throughout the programming world. They pop-up all
01:15the time and chances are if you ever have to build script that validates form
01:20fields or works with data in some way, you've come across the need to process
01:26text patterns. That's where regular expressions really shine.
01:30Using regular expressions, you can perform all kinds of searching and
01:34manipulation operations on text that would otherwise require very complex
01:41pieces of script. I'll show you what I mean in just a moment. Regular
01:44expressions are created using either the RegExp Object or using a special
01:51literal syntax inside your script.
01:53We will get into that in a minute, but I thought it would be instructive to see
01:57the relative power of regular expressions by taking a look at solving a common
02:03problem and then solving the same problem using a regular expression. So let's
02:08jump over to the code and take a look at what I'm talking about.
02:13So here I'm in the code. I want you to imagine for a moment that we had a
02:18requirement in our script to take a string of characters and write a function
02:23that makes sure that the string only contains alphanumeric character, that is,
02:29your lowercase a-z, uppercase A-Z and the digits 0-9.
02:36Now if you were to write that using regular script, like I have done here,
02:41you can see that's not a trivial thing to do. I have a function here called
02:44testOnlyAlphaNum. In fact, what I should really do is name it, according to my
02:49Hungarian notations, as bTestOnlyAlphaNum because it returns a Boolean.
02:54I'm going to name the same thing down here in the onClick handler. I'm going to
03:00alert(bTestOnlyAlphaNum).
03:04So let's take a look at what the function does. It takes a string as an
03:07argument. If the string's length is 0, well, then obviously it doesn't contain
03:12any alphanumeric characters. That's why it's false right away. But if it does have
03:17characters in it, what we need to do is loop over every one of the characters
03:20and see if any one of those characters is not an alphanumeric one. If any of
03:25those characters are not alphanumeric, we can immediately return false.
03:29So here we have a loop. The loop starts at 0 and loops over all the characters
03:34in the string. For each character, we extract the character code at the
03:39position where the index currently is. Then we test each character code. So 48
03:46and 57 correspond to the numerical digits 0-9. 65 and 90 correspond to
03:52uppercase A-Z. 97 and 122 correspond to lowercase A-Z.
03:59So if anyone of the characters in this string is outside any of these ranges,
04:04we know immediately that we don't have a string that only has alphanumeric
04:07characters in it. If we make it all the way down here however, then we passed
04:11all the tests and the string has only alphanumeric characters in it and
04:14we can return true.
04:16So let's test this out in the browser and see what happens. So I'm going to
04:21type in abc123 and I'm going to Test. Okay, and that's true. It looks like
04:27we've only got alphanumeric characters there. I'll put in some capital ones.
04:31Okay, so far so good. Let's put in an exclamation point. Now it's false. Yeah,
04:36that's not an alphanumeric character. What happens if I put a space at the front?
04:41Yeah, that's also a problem.
04:43So it looks like the piece of script that we have written does a pretty good
04:47job of detecting characters that are not alphanumeric, but I want you to just
04:52watch what happens when you use a regular expression. Using a regular
04:55expression, I can replace all of this code right here with the following line.
05:00I'm going to return (strToTest.match() != null). What I'm going to match it
05:11against is inside these two lashes. I'm going to type ^[a-zA-Z0-9] + $.
05:29Now don't get freaked out by what I'm typing here. This is not some really hard
05:33to understand code. We'll cover this in the following examples, but what I'm
05:37defining here is a regular expression that matches lowercase letters, uppercase
05:43letters and digits, starting at the beginning of the input and at the end of
05:48the input. That's what these two characters mean.
05:50So now I'm going to comment all of this out and just run this example using
05:58that one line of code. So we are going to browse this. Up it comes, asd1234,
06:07some capitals. You can see it matches the rules of the game. All right, now
06:12let's put some other stuff in there. Let's put like # sign. Test that. No,
06:17that fails the test. Let's put in 0-1. That fails the test too.
06:25So you get the idea. Basically, what I have done is-- let's go back to the code.
06:29You can see I have replaced all of these lines of code with this one line of
06:33code right here. All it's doing is taking some patterns I have defined and
06:38matching it against the string and returning whether or not that's equal to
06:42null to see if there is a match.
06:44So that's the power of regular expressions. Now that we have seen it in action,
06:49let's go back and see how we define these and how we work with them.
Collapse this transcript
Using repetition within expressions
00:00What we are going to do in this example is try to build a pattern that matches
00:04US postal codes and suppose we had a task before us to validate some postal
00:10codes that were coming in from a form, and we had a function we need to write
00:13called bTestPostalCodes. So it's going to return a Boolean value based on
00:17whether or not the string that it has given matches a US postal code.
00:21So we are going to do this using regular expressions. Well, we are going to
00:24start off by saying if the string to test is null or the length is 0 then it
00:39means go ahead and return false because we know that we don't have a postal code.
00:43On the other hand, we need to check now if the postal code matches a pattern.
00:49So let's return strToTest.match and don't worry too much about the
00:59match function. I'll come back to it in a little while. All you need to know
01:03for now is that if it returns null, then the match failed. Otherwise, if it
01:07returns not null, then the match succeeded.
01:10Okay, so now we are going to write our regular expression, so we can do opening
01:13brace and then beginning of input and then we are going to say we are looking
01:16for backslash. That's digits and there has to be five digits followed by a
01:25dollar sign, which means end of input and a closing slash. So let's try this
01:31out in the browser and see if that works.
01:35Okay, so I'm going to enter some text, okay that clearly fails, I'm going to
01:39enter nothing. That fails. Let's enter some digits, 1, 2, 3, 4, 5, 6.
01:45That fails because you have to have only five. So let's take off that one and see if
01:50that works. Hey! It worked. Okay, so we've got a pattern now that matches postal codes.
01:55Now, the problem though remember is that postal codes in the US can have an
01:58optional dash followed by four more numbers and that's not going to work
02:03because our pattern isn't expecting that, we need to fix that. So let's go back
02:06to the code and see if we can find a way to fix that. So remember the way that
02:10you make things optional is by putting a question mark after them because
02:16question mark means zero or one times.
02:19So what we need to do is inside parenthesis to make a little group and we'll
02:23come back to this. So we are going to put a dash character and then we are
02:27going to put a /d for digits and then the number 4 and I need to put a question
02:35mark there. So now we got a group here that says a dash followed by four digits
02:41and the question mark means zero or one times.
02:44So in other words, this guy right here is optional, if it zero times that
02:49matches, if it's one time that also matches, but not two times or anything more
02:54than that. So now let's go back to the browser and we'll put in some text. That
03:00still fails, and we'll put in 123456. That still fails. We'll put in
03:07five-digits. That works. Okay, now the moment of truth, we'll put in a dash by
03:12itself, okay that fails. We'll put in four numbers and that works. Okay, so now
03:19we have built a pattern that matches not only five digits, but five digits and
03:24an optional four characters. So that works. That works, everything else seems
03:32to fail. So now we have built a regular expression that we can use to validate
03:37US style postal codes using character repetition and character classes in order
03:43to match a pattern.
03:45Okay, so now let's take a look at our next example, we'll see how we can do
03:49string processing using regular expressions.
Collapse this transcript
Understanding alternatives and grouping
00:00Now that we have seen how to build regular expressions that match character
00:04classes and repetition and optional elements, we are going to take a look at
00:08how you can match possible alternatives and how to group things together.
00:12Now we saw a little bit of grouping in the previous example using parenthesis, but
00:16parenthesis are actually useful for more than just grouping. So we'll take a
00:19look at what those are used for in a moment.
00:21Now to define a regular expression that can match possible alternatives,
00:25you use the vertical bar character and to group things together you use parenthesis
00:31like I mentioned. So let's take a look at some examples. So to match the string
00:35hello or the string goodbye inside the slashes for the regular expression,
00:41you would write the word hello separated by a vertical bar and then followed by the word goodbye.
00:48If you wanted to match four digits or five characters, you would write /d and
00:54then 4 inside braces and in the vertical bar meaning or and then /w for
00:59characters followed by the 5 inside the braces. So that matches 4 characters or 5 braces.
01:05Now if you wanted to match a US postal code with an optional four digits or the
01:10word wow that has to come at the end of the string, you would write something
01:14like this. You would write the beginning of input, which is the up arrow
01:17character there. Then inside parenthesis you would write /d and then 5 in braces,
01:24that's five-digits, and then again in parenthesis a dash followed by the
01:29/d and 4 in braces and then close parenth with a question mark, and that means
01:34five digits followed by 0 or 1, of the dash with four digits pattern,
01:40followed by the dollar sign, which means end of input, vertical bar, which
01:45means OR, and then the word wow with dollar sign, which means come at the end of the string.
01:50Now using the regular expressions, you can also define what are called
01:55sub-expressions within an expression. This is what parenthesis also are used for
02:01and the reason you do this is because you can define sub-expressions that
02:05can later be extracted from the larger matching result. Let's look at the
02:12example of why you would want to do this.
02:14To match a phone number like 1234567, you would write a regular expression that
02:19looks like this. You have /d, which means digits, and then 3 in the braces
02:24followed by a dash, followed by /d and then 4 in the braces and that would
02:29match a number with this kind of pattern. To be able to extract the individual
02:34portions without having to write additional regular expressions, you simply
02:38enclose them inside parenthesis.
02:41So it's the same regular expression only I have now enclosed the exchange part
02:45of the number and then the last part of the number inside parenthesis.
02:50The reason you do this is because you can then refer back to these sub-expressions
02:54by writing a backslash character followed by a number and the number is the
02:59index of the sub expression to refer to. So this sub expression would be /1;
03:05this sub expression in parenthesis would be /2. It's a little abstract.
03:10So let's take a look at example of why you would want to use this. Suppose you
03:14had the following regular expression: braces with a single and double quote,
03:18then you have more brackets with an up arrow character and then a single and
03:22double quote followed by a star and then brackets with a single or double quote.
03:27Now remember from our earlier discussion on patterns, what this
03:32expression basically says is match either a single quote or a double quote then
03:37anything that's not a single or a double quote, zero or more times followed by
03:42a single or a double quote.
03:44So what this essentially is matching is a string of text inside quotes.
03:48However, this expression does not require that the closing quote match the
03:55opening one. Because either a single or a double is going to match then here
04:00either a single or a double is going to match. So you could have a string that
04:04opens with a double quote and closes with a single quote and that would cause a match, [00:04:8.15] but that's not really what you want. What you want to do is force this
04:11part of the expression to match whatever happened up here.
04:15So you do that by enclosing it in parenthesis and then referring back to it.
04:20So let's take a look at the new expression. The new expression is in parenthesis,
04:24you had the braces and a single or double quote followed by in brackets, the up
04:29arrow character and then single or double quotes with a star. So that means
04:33match either a single or double quote and then anything that's not a single or
04:38double quote and then the /1 means to close the expression, match whatever
04:44happened in this parenthesis group up here.
04:46So if this group matched a single quote, then you got to require that here;
04:51if this match was a double quote then it's got to be the same thing here. This is
04:55a very, very powerful part of regular expressions, the ability to remember
05:00matches of sub-expressions that happened earlier on in the pattern. Now I said
05:06earlier that the match function had some additional features to it. The match
05:12function gives you the ability to refer to parenthesized sub-expressions inside
05:16your script and we'll see that just a little bit later.
05:20Okay, one more thing I want to cover quickly and that is specifying match flags.
05:25Up until now, all the expression patterns we have written had been case
05:29sensitive and they stop at the first match even if the source string has more
05:36potential matches in it. So if we had a string that had multiple postcodes in it,
05:41the expression that we have written up until now wouldn't have matched those.
05:45The way you change this behavior is by using match flags in your regular
05:51expression. To define a match flag, you put it outside the closing slash of the
05:56regular expression.
05:58So to make a search case insensitive, you would simply write the string you
06:03want to have matched and put the letter I outside the closing slash and that
06:07would now match all these different examples, hello, the upper case Hello, some
06:11of the characters could be capitalized and some not, that kind of thing.
06:15To match more than just the first one, you would use the g flag for global.
06:20So to match all the hello strings in a given source of input, you would write
06:26hello and then g and this would match every single hello string in the input,
06:31now all lowercase obviously, and you can combine them. So G and I together
06:36would match all the hello strings regardless of capitalization.
06:39Okay, so we have come to the point now where we can stop and take a look at
06:42what we have learned and apply in our next example.
Collapse this transcript
Using alternatives and groups
00:00Okay, so here we are back in the code again and this is the code where we left
00:04off from the postal code example. So what we are going to do here is show some
00:11ways of doing alternates and groupings. So what I'm going to do is modify our
00:19existing regular expression which matches postal codes and I'm going to group
00:25this inside of parenthesis and I'm going to put a bar here and I'm going to put
00:32the word wow followed by a dollar sign.
00:35So now I have modified this so that you can see it's going to accept a postal
00:39code or the word wow. As long as the word wow comes at the end of the string.
00:44So let's browse this and see what happens. The word wow by itself if that
00:51matches, the wow hey that doesn't match. The postal code part should still work.
00:59Yup! And it does, okay and just to make sure that the optional part works
01:05too. Yup, that works too and put a whole bunch of characters in there with wow
01:13and that didn't work and if we make it at the end of the string, that works and
01:19then finally we put a postal code in there and that works too.
01:25Okay, so now that's an example of building expression that has an alternate in
01:30there, so the bar character means choose between this or match this. In fact,
01:38I can put another one in there, and in this case if I wanted to come at the start
01:44of the sentence I can say match the word hey as long as that comes at the
01:48beginning. Now if I put in hey that works or if I put oh hey, that doesn't work.
01:59Okay, you get the idea. Now let's go back and build an expression where like in
02:06the example in the slides we match a string that has a sub expression that we
02:12refer back to. So let's comment this guy out, and make a copy. Let's build the
02:20expression that we saw where we require an opening quote to match the closing quote.
02:27Okay, so here we have our expression and we are going to have a single or a
02:32double quote followed by anything that is not a single or a double quote zero
02:41or more times followed by a single or a double quote. As you can see, we have
02:48built an expression that now will match a quote at the beginning, some content
02:52and a quote at the end. Let's try that out. So I'm going to say hey there, and
03:00that works but notice it also works if you put a single quote at the end and
03:05double at the beginning or I put a double at the end and single at the beginning.
03:11Yeah, I don't want that behavior. What I want is I want the ending quote to
03:16match whatever the beginning quote is. So let's go back and fix that. So
03:21remember by putting things in parenthesis, we can remember them for later. So
03:25by putting this guy right here inside of parenthesis group, I can then go back
03:31to the end of the expression here and write backslash 1 (/1) and what that's
03:36going to say now is okay remember this match right here in this sub expression
03:42and then at the end of the expression the /1 means the match at this position
03:48the patter has to match whatever we came across at our first sub-group right
03:53here and by the way, you can have multiple sub groups.
03:55You could enclose multiple things in parenthesis and refer to them using
03:59backslash and then numbers 1, 2, 3, 10, 20, 50 whatever. So now let's try this
04:06in the browser and see what happens. So now what should happen is if I type a
04:10double quote and then some text, if I type a single quote that should no longer
04:15match and in fact it does not. Now I'll type a double quote, that should match
04:22and it does, okay. And just to make sure for completeness we'll do two singles, okay.
04:29So now we have fixed the expression to make sure that the opening quote and the
04:33closing quotes match. Now we know enough to move on to some more advanced
04:39string processing and using some of the methods on the string and rex objects,
04:44looking more into those.
Collapse this transcript
Processing strings
00:00The real power of regular expressions starts to shine when you use them with
00:06string processing: searching for content, replacing content, manipulating content.
00:11That's where regular expressions really add to the power and the value
00:16that you have already seen. To use regular expressions to search text,
00:20the string object in JavaScript provides a few methods to help you with this.
00:25We use the string search method to find occurrences of patterns and where they
00:31occur in the string.
00:33You saw the global flag that we talked about in the match flags in the previous
00:37example. String.search does not support global searches. It returns the
00:43character position of the match if it finds 1 or it return -1 if there are no
00:49matches. Now since search does not support global searches, if you want to find
00:56more than one instance of a pattern, you will need to slice up the source
01:00string as you go, alternatively you can use the match function, which we'll see
01:06a little bit later.
01:07The string match function is a more powerful version of search. It always
01:11returns an array of results and it can perform global searches. Now the array
01:18that comes back from match is different depending on whether you do a global
01:22search or a non-global search. For a global search, the returned array always
01:27contains all of the matching parts of the source string. So if you did a global
01:32search on the word hello and the string that you are searching has the word
01:36hello five times in it, then the array that comes back from match on a global
01:41search is going to having five elements all of them with the words hello in it.
01:45For a non-global search, the array that comes back contains the full match
01:51along with any of the parenthesized sub patterns similar to what we showed in
01:58the last example with the /1 and the parenthesizing of the quote matching and
02:05finally the string.replace function is a powerful method for finding and
02:10replacing content in a string using regular expressions. The way you call it is
02:16you call replace with a regular expression and the string that you would like
02:21to use to replace the match with or you can pass in a function that generates
02:28the replacement text.
02:29It's very powerful and we'll see an example of that in just a few moments.
02:34But for now, let's take a look at how we can search for text using the string.search function.
Collapse this transcript
Using string.search()
00:00What we are going to do is use the Search function to search for content using
00:05a regular expression. So you can see here in the source I have got a paragraph
00:10that has the word JavaScript in it a bunch of times and we are going to use
00:16this as the example of our source strings. You can see that's right here in the source code.
00:20Now here is the button that when this button gets clicked, that's what's going
00:25to trigger the searching function. So let's switch over the source fully.
00:31A couple of things I want to point out, just some housekeeping stuff. The onload
00:35event for the window is a function which hooks up the button click to call the
00:39doSearch method and the doSearch method is where we kick off our examples.
00:44So the first example we are going to write is called findString and findString
00:48is going to take the string that we are searching which is going to be the
00:52inner HTML of that paragraph and it's going to look for the word JavaScript and
00:57it's going to do it with a case insensitive search.
01:00So we need to write the findString function up here. So let's do that. Now
01:06remember, we are going to use the Search function on the string object to do
01:09the searching. Search returns -1 if the pattern is not found and returns
01:14anything else if the pattern is found.
01:16So what we are going to do is write var result = sourceString.search and [00:01:287.87] we're going to pass in the patternToFind. Say if (result == -1), alert ("Pattern
01:42not found"). Otherwise, alert ("Pattern was found at position: " + result).
01:59Because the result of the search is the index where the match was found.
02:04So let's format this a little bit better. Here we go.
02:05So let's try that out and see what happens. I'm going to browse this and
02:11remember we are looking for the word JavaScript. We'll click Find. It says
02:15Pattern was found at position: 14. So it worked. The reason it worked was
02:20because the pattern that we are looking for is JavaScript and we are doing a
02:24case insensitive search.
02:26Now if we took off that match flag and we tried this again, then we see the
02:33pattern was not found because we are not doing a case insensitive search
02:36anymore. So if we did something like this, okay now it works again.
02:49So let's go back into our example, put the case insensitive back on there,
02:55change this back. Now let's do something a little more fancy. What we are going
03:00to do now is see if we can find a way to count the number of matches in the
03:06source string.
03:07Now remember I said earlier that the match function actually does this for you,
03:12but we are going to see if we can build our own here. So we are going to write
03:16the countMatches function right here and again, it's going to take the source
03:20string, it's going to look for JavaScript and we are going to pass in the
03:24length of the pattern that we are looking for. That's 10 characters right there
03:29and that will become obvious in a moment.
03:31So in the countMatches function, what we need to do here is declare a couple of
03:36variables. There is the result and we are going to have a temporary variable
03:42called pos. There we go and we are going to write var tempString = new String
03:54and that's going to be the sourceString. So while ((pos =
04:04tempString.search(patternToFind)) != -1. So as long as we are finding patterns,
04:18we are going to count. So we are going to increase the result.
04:24Now we need to advance the position pointer past where the result started. So we are
04:30going to say pos += patLength and now we are going to take the substring,
04:41.substr starting at the position and going to the end,
04:46and then we are going to say alert ("Pattern was found " + result + "times.");
05:06Now with the event all hooked up, let's browse this and see what happens.
05:10All right, I'm going to click Find. It says Pattern was found 3 times. Okay, good.
05:16So now let's go back, put that space and take off the case insensitive part of
05:24the search. Browse that again, now that time the pattern was found 0 times.
05:31Okay, so we successfully implemented a pattern finding function as well as a
05:37way to count the number of matches. Let's move on now to seeing how the match function works.
Collapse this transcript
Using string.match()
00:00Okay, so in this example we are going to use the match function. Recall from
00:05the slides part of the lesson, I mentioned that match returns an array of
00:10results and the array that it returns is different based upon whether you are
00:14doing a global search or a non-global search and we are going to look in both
00:19examples here.
00:20So I have the same document almost that I had in the previous example, modified
00:25slightly. I have got two buttons, one for doing a Global, one for doing a
00:28Non-Global Match and I have got a couple of phone numbers in here. So here is one,
00:33here is two, and here is three.
00:36In this example, we are going to use the match function to find all the phone
00:41numbers in the document. So let's go back to the source. So what we have here
00:47is when the window loads, we are hooking up some event handlers for doing both
00:52the global and non-global matches and that's where these guys get kicked off
00:57from right here, these event handlers.
01:00So we need to write the findMatchesGlobal and findMatchesNonGlobal functions.
01:06So let's start with findMatchesGlobal. What we are going to do is in
01:09findMatchesGlobal, we are going to search the source string for this pattern.
01:15You can see the pattern here is 3 ASCII digits with a dash in the middle
01:20followed by 4 ASCII digits. For the Global Match, we have the g here on the end
01:27of the regular expression. So let's go ahead and write the findMatchesGlobal
01:31function and see what happens.
01:34So for the Global Match function we are going to type var result =
01:39sourceString.match. And the patternToFind is being passed in. Now remember in the case
01:48of the global match, what's going to happen is the array that comes back
01:53from the match function is going to have all of the matching patterns that were found.
01:59So we are going to alert "Found a total of " + result. length + "matches: " and then we're going to add in
02:21the result array, .join, and this basically takes all the elements and joins them together
02:29using this string. So it's going to be a comma between each one of them. Okay,
02:34that looks about right and let me format the document so it looks a little bit better.
02:40There we go. Let's fire this up in the browser and see what happens.
02:46So for the Global Match, we should get a result of an array with 3 phone
02:52numbers in it. There is one, there is two and there is three. So I'll click
02:56Global Match and sure enough we found a total of 3 matches and then here is
03:00each one of the elements in the array. So you can see it extracted all the
03:04phone numbers from the text that was in the paragraph.
03:09So let's go back to the code and just for a quick review, you can see that we
03:13did that because here is our pattern. Here is the 3 digits, 4 digits, so on.
03:22Now let's do the Non-Global Match. The Non-Global Match a little bit more
03:26interesting because remember you can use the parenthesized results from the
03:32sub-expressions in the output.
03:34So let's see what that looks like. We are going to say var result =
03:42sourceString.match and I'm going to match the pattern. Now remember,
03:50let's conclude really quick. There is no g flag on this one, so this is going to be a
03:54Non-Global Match.
03:58Then we are going to say alert "Found a match" and we're going to say result 0.
04:11So result 0 is going to contain the entire matching pattern that was found.
04:16Then we are going to add on to that "\nThe exchange part of the number was: " +
04:30result 1 + "\nThe rest of the number was: " + result 2.
04:50Now let's try this out and see what happens.
04:53So for the Global Match that still works, 3 matches,
04:56all the phone numbers. For the Non- global Match, it says Found a match from
05:00the first phone number. The exchange part of the number was: 555 and The rest
05:05of the number was: 1212. Does that match? Yeah, that worked.
05:08So we used the parenthesized part of the pattern here to remember the different
05:18parts of the number that were matched. Now this is very powerful. You can use
05:21this to split up all different kinds of patterns that have different parts to
05:25them. For example, URLs, they start with http:// and then they have the
05:32computer that you are going after versus the domain, versus the top level
05:35domain, like .com or .net or whatever followed by the rest of the URL which is
05:40the path to the file. You can use regular expressions to slice up all kinds of
05:44patterns that have interesting sub-patterns in them.
05:48The last example to look at is using the string replace function to manipulate
05:54text using regular expressions. That's we are going to look at next.
Collapse this transcript
Using string.replace()
00:00In this example, we are going to use the Replace function to manipulate text
00:04using regular expressions. So once again, I have a paragraph here with a bunch
00:10of content. A couple of things I want to point out. JavaScript in this
00:14paragraph is spelled a couple of different ways. Here it's with a capital J,
00:18here it's got a capital S and here it's all lowercase. I just want to point
00:23that out to you, so you can see what's going on in a couple of minutes when we
00:27are running our code.
00:28So what we are going to do here is use the string replace function to
00:33manipulate the text in this paragraph. Let's go to the source. Once again,
00:38we have our windows onload handler hooking up the onclick function of the button
00:43to do the replacement.
00:45We are going to do two different kinds of replacement. The first we are going
00:48to replace by using a string. Then recall earlier in the lesson I talked about
00:53how you can call the replace function with a function that you want to use to
00:58generate the content that gets replaced.
01:00So let's take a look at how we write the replace string function. Since that's
01:06our first example, let me format the code. All right, so I'm going to say here
01:12var result = sourceString.replace and we are going to say replace the
01:23patternToFind with the strReplace that's being passed in.
01:29So let's go down and take a look at how this is being called. The replace
01:33string function is being called with the inner HTML content of the paragraph in
01:38my document. We are doing a global case insensitive search of the word
01:45JavaScript. We are replacing it with this literal string right here. So let's
01:51see how that works.
01:55Then after we do the replace, we are going to do
01:58document.getElementById('sourceText') .innerHTML = result. So the replace
02:12function will come back with a string that has all of the matching patterns
02:17replaced by the string we want to replace it with. Then we take the result
02:21string and put it back into the document as replacement for the source text in
02:26the paragraph.
02:27Let's put this in the browser. Okay, so now look at all the words JavaScript.
02:31Here is the first one, here is the second one right here, here is the last one.
02:35When I click Replace, they should all be capitalized properly and indeed, they
02:39are. So they all got replaced with the proper capitalization of the JavaScript name.
02:46That shows an example of how you can use regular expressions to replace
02:51patterns that are found in text. So you can imagine some examples where you
02:57look for phone numbers that don't have the area code in parenthesis and put
03:03them in their proper order or you can look for phone numbers that don't have a
03:071 in front of them and put them in, things like that. It's a very powerful
03:10searching and replacing mechanism, but it gets better.
03:13So let's do the better part. I'll comment this one out and uncomment
03:18replaceWithFunction. Now in this case we are doing pretty much the same thing.
03:22We are saying search on the content of that paragraph, do a global case
03:28insensitive search on the word JavaScript, no matter how it's capitalized and
03:34replace it with this literal string, but we are going to have a little bit of a twist.
03:38So let's see how that twist works. So back up in replaceWithFunction, I'm going
03:44to write var result and this is going to be the string that gets put in as a
03:50replacement. sourceString.replace and this time we are going to replace the
03:57patternToFind with a function. The function is going to return the string
04:15"JavaScript" + gCount variable that increments each time. Then I'm going to
04:26say document.getElementById ('sourceText').innerHTML = result.
04:39Then down here I have got to declare my global variable var gCount = 0. So now
04:51what we are going to do is return the word JavaScript with a count on the end.
04:56Let's see if that works. Click Replace and you can see that now all the words
05:03will be replaced by the word JavaScript and an incremental counter on the end
05:07of each one. So here is JavaScript 0, there is JavaScript 1, there is JavaScript 2.
05:11Okay, so I hope that this does a little bit to illustrate the power of using
05:16regular expressions in manipulating text in your documents and shows you how to
05:23replace content using regular expressions. It's very powerful. I highly
05:27encourage you to experiment with these examples, play with them, try out
05:32different things. This kind of technique can save you a lot of time and really
05:37boost the performance of your scripts.
Collapse this transcript
Understanding the RegExp object
00:00I am going to finish off this chapter by looking at the RegExp object. Up until
00:04now, we have been working with regular expressions using the // syntax and
00:08manipulating them using strings. However, there is a RegExp object, which is
00:14provided by the JavaScript language and interpreter in your browser, and it's
00:18also pretty powerful and useful so I want to cover that before we finish.
00:22So, using RegExp is just like using the // syntax; it's just more object
00:28oriented. It's kind of like using new string instead of the quote characters in
00:32your script. Now, the RegExp object has its own properties and methods just
00:38like other objects in JavaScript. So let's go over each one of these and we'll
00:43talk about each one and then will show an example of how you can use one of the
00:48most powerful regular expression functions in JavaScript.
00:52The Regular Expression Test method tests the regular expression against a given
00:58string. It's like doing the same thing with the String Search method. Whereas
01:03with the String Search method you call String Search with a regular expression
01:09pattern and it returns whether or not it was found. RegExp.test is basically
01:15the reverse; you are calling a string into a regular expression and seeing if it matches.
01:21So, I'm not actually going to show an example of that one because it's very
01:24simple and the syntax is easy to look up, so we are just going to skip that
01:29one. But just so you know the same way that you can execute patterns against
01:33strings, you can also execute strings against patterns. That's all you need to
01:36think about of the test method. It's the reverse of String.search.
01:40The RegExp.exec method is a very powerful expression matching function. It is
01:45perhaps the most powerful of all the regular expression functions that we have
01:49looked at so far. And we'll take a look at that in next example, but for now
01:53let's finish off the rest of the properties.
01:55The RegExp.ignoreCase property is the same as using the little "i" flag in the
02:02// syntax and as you might guess the RegExp.global property is the same as
02:08using the "g" flag in the // syntax. So setting these properties to true is the
02:14same as having the "g" or the "i" flag in your regular expression pattern.
02:20In addition, the RegExp.source property is the read-only source string of the
02:26pattern. So if for some reason you want to refer back to the pattern in your
02:30script, you can use the source property to do that. And then finally, the
02:35RegExp.lastIndex property that refers to the position index of the most recent
02:40match that this object matched against.
02:43Now that we have taken a look at the properties and methods for the RegExp
02:48object, let's have a look at an example that uses the Exec function to do some
02:53very powerful string matching and combine some of the features that we have
02:57seen up until now using different objects and different methods.
Collapse this transcript
Using RegExp.exec()
00:00This example is going to illustrate the use of the Regular Expression object's
00:05Exec function. So recall from some of the earlier examples that in order to do
00:11things like looping over all the matches in a string of text, you had to do some
00:16pattern length calculation or some other tricks to get each one of the patterns
00:20in the entire global sting. Remember also we had to use the match function to
00:26get an array of all the results including the parenthesized ones.
00:31The Exec function does all of this and it does it all within the scope of just
00:35one function. So here is what we are going to do. I have an example document
00:40here and as you can see it's the same content as we used in the match example
00:45with the phone numbers. We are going to use the Exec function to extract the
00:50phone numbers from the document and loop over each one of them, one at a time.
00:55So using the Exec function, we are going to loop over each one, figure out the
00:59start index of where it appears and get some information about each number and
01:04then go on to the next one.
01:07So, let's go ahead and write that function. So, we'll switch over to the source
01:11and you can see here that we have a button and the button's onClick handle gets
01:18setup during the window onLoad function which calls doExec. And all doExec does
01:23is it calls findMatchesWithExec and it passes in the pattern for the phone
01:29numbers that were used in the search and this is a global pattern. And it uses
01:34the innerHTML of the sourceText element in the document and that's this
01:39paragraph right here.
01:40First I'm going to format the code a little bit, there we go. I'm going to
01:45write var result;
01:47I'll write while ((result= patternToFind .exec(sourceString)) !=null).
02:10Then we're going to have our little loop here. And the loop is going to say
02:13alert ("Found a match: " ), and the index zero of the result array that
02:24comes back from the Exec function has the full match that was found. So we are
02:30going to write result 0. This will be the entire
02:33phone number as it finds it. The Exec function also tells us the position that
02:38it found it at. So we are going to write at position + result.index.
02:46So the index portion of the result that comes back tells us where the match
02:52took place in a character index in the string. We're not done yet.
02:58We're also going to write "will search next starting at," and this is where we use
03:13the patternToFind.lastIndex property.
03:21So when Exec finds a match, it automatically sets the last index property to
03:27the first character index after the string that caused the match. And this is
03:32what allows you to do looping using the Exec function. However, there is more.
03:39So we'll add some more, "\nThe exchange part was: ".
03:49In addition to the result array containing the full match, it also matches the
03:54parenthesized sub expressions. So we can do something like this.
04:11And we'll put in result 2.
04:15So, now we have a loop that will loop over all of the phone numbers one at a
04:20time in the string, match each one, automatically advance to the part of the
04:25string to look for the next one and extract out the parenthesized expression
04:31that we have here. There is the exchange and then the rest of the number right there.
04:35Okay, so let's run this in the browser and see what happens.
04:41So, it should find three phone numbers and extract out information in each one.
04:45So I'm going to click Find Matches. You can see that it found the first one,
04:49found a match and there it is at position 43 and will search next starting at
04:5451. So it's automatically incriminating the character index pointer to be after
04:58this part of the phone number. And you can see that it was able to extract out
05:01the two parenthesized portions of the number. There is the exchange part and
05:06the rest of the number. Let's do the next one.
05:08Okay, see, it found that one too. Found this guy right here at position 104 and
05:13it's going to start searching again at 112, because it's going to pass that
05:17point and it extracted both parts of the number and then finally it found
05:22the last phone number. Position 140, starting again at 148, and there is the two parts of number.
05:28So you can see that the Exec function is the most powerful one. It's sort of an
05:33amalgamation of using the search and match and test functions from the rest of
05:41the regular expression function universe. However, what we are doing here is
05:46using the properties all in one function to loop over all of these matches and
05:50extract information and automatically advance to the next part of the string
05:54where we are matching to.
05:57Okay, well, that concludes our regular expression coverage. Hope you found this
06:02useful and you should go out and start using regular expressions in your code.
Collapse this transcript
7. Practical JavaScript Examples
Setting context
00:00All right, we have reached the point in the course now where we can start
00:03looking at some practical examples that put into practice the things that
00:07we have learned so far. Now, I'm really strong believer in the idea that in order
00:11to get a clear idea of how something works you should probably see it in action
00:15in a focused example that really clearly illustrates the point.
00:19So, I have collected a bunch of examples that illustrates some of the points
00:23that we have been working with throughout this course. I have also provided
00:26the code that you can use in your own projects. So, we'll take a look at some
00:31example code that demonstrates these techniques.
00:34To be specific, we'll look at things like how to determine if the window is
00:39already open. We'll look at ways we can improve the interactivity of your forms.
00:44We'll see code that makes use of information that's already in the web page
00:48to provide a better experience for the user.
00:51We will look at ways you can improve the readability and interactivity of
00:56tables in your pages. We'll see really a neat example of how you can edit the
00:59content of the page in place and you can use this technique in several
01:03different scenarios. Then we'll look at a way that you can adapt the layout of
01:06a page to changes in the window size.
01:09I have also gone ahead and taken my own advice and I have grouped my event
01:13handling code into a reusable module that you can use in your code. So, before
01:20we get started, why don't we take a look at that code right now? Okay, so here
01:24I am in the code. This is the event handling module that I have created which
01:28can be reused. So you see I have declared my com_joemarini object up here and
01:34if you don't like that you can change to whatever you want, but I just named it this
01:37because I knew it would be unique.
01:39Now, the syntax you have seen here might be a little bit different than you are
01:42used to seeing. For example, you may not be used to seeing objects declared
01:46using this kind of syntax. So just for illustration, I want to point out that
01:50doing something like this. var obj = new Object(), that is functionally the
01:57same as doing something like this.
02:03Okay, those two are equivalent.
02:04It's the same as if you were to do something like this with arrays. You can do
02:08var myarray = new Array(). You can also just shorten that syntax by writing
02:14something like this.
02:20So, when you see notation like this or like this, it's just shorthand for
02:24declaring the objects. You might also not be familiar with the way that I'm
02:28adding properties and methods to the object here. This is called object
02:32notation or JavaScript object notation.
02:35What I'm essentially doing is instead of saying var obj = {}, once I've got that,
02:41instead of saying obj.property = function(), what I'm essentially doing
02:50here is I'm declaring all of the properties of the function at once. So, right
02:56inside the braces what I'm saying is myproperty: and then giving it a value, or
03:08declaring a function. Those two syntaxes are functionally the same. So,
03:13it's just a shorthand way of declaring an object that has properties in it.
03:16So you can see what I have done here is I have used exceptions to detect the
03:21situation where this object is already defined and it's not an object type.
03:26Well, something must be wrong there. So I throw an error exception here and
03:31I'm also creating a sub object called events on my top-level namespace. I have
03:38given it a name, I have given it a version and then I have gone ahead and
03:41collected all of the cross-browser event handling code that we wrote in an
03:45earlier chapter into this object.
03:48And we'll be making use of this module throughout the examples that we'll be
03:51looking at. So if you are ready then let's go ahead and get started with our first example.
Collapse this transcript
Improving forms
00:00Okay, let's begin by looking at a way that you can improve some basic
00:04interactivity in your forms using a combination of JavaScript and the DOM and some CSS.
00:11Here I have got a basic form. A couple of things I want to point out. First,
00:15you notice that the outlines of the form elements are kind of soft and gray on the
00:21borders, except for the one that currently has the input focus. I have also
00:24got labels over here and you can see that as I mouse over the labels,
00:29the pointer changes to a pointy hand indicating that you can click on it. So let's
00:34play with the form a little bit, see how it works, and then we'll take a look at the code.
00:37So first you can see that when the form is loaded, the input focus defaults to
00:42the first input element that's in the form. You can also notice that the
00:46background of the text area has changed to be slightly yellowish, indicating
00:50that that's the currently active field, and the border has become darker,
00:54it's a black color as opposed to the ones that are gray. This is a visual cue to the
00:58user of where the current input focus is. There is also red stars next to each
01:04one of the fields indicating visually that hey, this field is important.
01:09It's required. So let's play with the form a little bit and see what happens.
01:13So I'm going to click off this Message Subject, and click on to the Address field, and
01:19you can see that when I do that, the label for the Subject has turned red.
01:23That's a visual cue to the user that I have left out a piece of information
01:26that's probably pretty important. I should go back and fix that. Now that
01:30happened automatically and it happened before I tried to submit the form.
01:33I'm giving the visual cue to the user right away.
01:35Let's click back on to the Message Subject now, but this time I'm going to
01:38click on it using the label. So you can see that when you click on the label itself,
01:42the input focus goes back to the Message Subject and now the Email
01:47Address has become red, because I have left that field without filling it in.
01:51So let's type in the Message Subject, Hello there, and now I'm going to tab to
01:57the next field. Okay, you can see that the Message Subject field has now gone
02:00back to being black, indicating -- okay, looks like I have filled that in
02:03properly. All right, now let's type in an Email Address and let's just give it
02:06something that we know is wrong. Okay, now I'm going to click down into the
02:08Your Message field. You can see that the Email field is still red, indicating
02:13that I haven't properly filled it out. So, let's go back up there and type in
02:18joe@joe.com.
02:21Now we'll click down here, oh, okay, so now it's validated. We can see that
02:25because it's not red anymore. And then finally in the Your Message field,
02:28I'll say 'This is a message.' I'll tab off. Now you can see that all the fields are black
02:32indicating that we have properly filled them out, and we can submit the form,
02:36but let's see what happens if I try to submit the form without any
02:40content. So I'll just delete this and I'll delete this and I'll delete this,
02:45and I'll click Send Message, and you can see that a little error dialog popped up.
02:49It says hey, the fields that are marked Bold and Red are required.
02:52Please supply valid values for those fields before sending.
02:55So if I were to go back and fill those in again, now if I click Send, the form
03:05gets submitted. And alternatively if I'm in the middle of filling it out and I
03:09decide to start over again, I can click Clear field and start over and
03:13the form goes back to its default state. So you can see that this form has clearly
03:18got some nice little interactive features going on. Clicking on the labels,
03:21I have got the highlighted field changing. I have got some validation going on.
03:25So let's take a look at the code to see how that works.
03:28Okay, so here I'm in the code for the file that you just saw. I'm going to go
03:33to the Design view really quick. So this is the file and this is the HTML part
03:37of the document. So here are my form fields and my labels and all that and my buttons.
03:43So let's go back to the code. First thing I want to point out is right at
03:47the top. I have linked in a Style Sheet and I have got a couple of scripts
03:52here and the first script I'm including is that event handling module that
03:56I wrote that's reusable. And then I have got the JavaScript file that's local to
04:00this example right here, called improvedforms. So let's scroll down to a
04:04little bit. All right, here is the form itself. One thing I want to point out
04:08is nowhere on the form are there any event handlers or anything about
04:14interactivity. Okay, all you see is the markup. I have got some style
04:18information. That's pretty much about it.
04:21Okay, so let's go over to the JavaScript file. Couple of things going on.
04:27First, right at the top here I have got a few global variables that contain
04:31some information I'm going to be using in my form. So we have got some style
04:35information and some strings here. We've got a regular expression that we are
04:38going to be using and we've got some information here about invalid fields.
04:42Now notice how I have named everything so that it's easy to see what's going on.
04:45You can pretty much guess what these are by looking at the names and
04:48before we look at the filling in the code, you can see I have written a bunch
04:51of functions to do things like highlight and unhighlight form elements and do
04:55some validation of the fields. So down here at the bottom I have this line,
05:02the com_joemarini.EVENTS.addEventHandler. So this is the event handling module
05:07in action. It's adding an event handler. So when the window loads, we are
05:11calling a function called initFormElements and we are passing in a string
05:14called 'text'. So let's go back up and write that function and see how it works.
05:20Okay, so when the page loads, there is a bunch of initialization that
05:25has to take place and this is where all of that happens. So a couple of things
05:29happen right upfront. The first is I'm getting all of the text area elements in
05:33the form by calling the document. getElementsByTagName function and there is a
05:39loop here that loops over all the text areas and the reason we are doing that
05:43is because we are adding event handlers for the focus and blur events. So
05:47you can see that when the focus event happens, we are calling the function called
05:50highlightFormElement. And when the blur event happens, which is when an
05:54element loses focus, we are calling the unhighlightFormElement function and
05:59we'll get to those functions in a moment. But we need to do the same thing for
06:03the other input elements, not just text areas, but the input elements as well.
06:07So we are going to write some code for that. We are going to say inputElems =
06:13document.getElementsByTagName('input') and this is going to come back with an
06:20array of all the input elements and we are going to write a similar loop that
06:25we have above, say for (var i=0; i < inputElems.length and increment the variable there.
06:39Okay, now we have to do a trick here to make sure that we are only getting the
06:44input elements that are type of text, because remember input elements include
06:48things like buttons and other kinds of stuff. So that was the string that we
06:52were passing in and remember it contained the word text. So what we are going to
06:56do here is if the string for valid elements, .indexOf, and this is going to look for a substring,
07:06and we're going to look for inputElems. The one that we're looking at, .getAttribute.
07:14It's a DOM method for getting an attribute. And we're going to look at the type attribute.
07:24Is not equal to -1.
07:26So if we find the substring 'text' inside the type attribute of the element, then
07:33we are going to go ahead and do our little registration of events. So we are going
07:38to say com_joemarini.EVENTS.addEventHandler.
07:47And we're going to add the event handler on that input element.
07:52And we're going to add one for focus. We're going to call the highlightFormElement.
08:02And we are going to do the same thing for the blur event.
08:07So, let's copy and paste that. I can call it on blur and we'll
08:12call the unhighlightFormElements. Okay, so now we have written the code that
08:19will handle the focus and blur events for highlighting and unhighlighting the
08:24form elements. Now you might be asking yourself, well, can't we just use the
08:28CSS pseudo selector for focus and blur? And the answer is in Firefox, yes, you can.
08:33IE, however, does not support those pseudo selectors and CSS classes for
08:37focus and blur on form elements. So we have to write a little JavaScript to
08:41handle it in the cross-browser case.
08:44So the next thing we need to do is write the code is going to handle the Reset
08:50and Submit events on the form. So let's do that now. So I'm going to write
08:57com_joemarini.EVENTS.addEventHandler, and this time we are going to add the
09:05event on the form itself. So we are going to write document.getElementById and
09:13in the document, the form has an ID of 'form1'. I'm going to add the event for
09:19the 'reset' handler. We are going to add a function to handle the reset event,
09:23and the function is going to look something like this. So the first thing
09:31we need to do when the user hits the reset function is set the focus back to the
09:36first form elements, so the user can start typing. So we'll say
09:39document.getElementsByTagName and then we're looking for the input.
09:48We want the first one in that array. So we're going to say 0 and we're going to tell that to go ahead and take the focus.
09:56This will cause the first text field
09:58to have the focus in form. Now we need to go back and reset all of the
10:06labels in the form, from being in any invalid state that they might be back to
10:11being initially valid. So we are going to write a little loop here to do that,
10:17for (var i=0; i < document.getElementsByTagName...
10:27So we're going to do this for every label in the form.
10:31And we want to loop over the length of the array.
10:39What we're going to do is say
10:41document.getElementsByTagName('label') and we're going to look at each individual one.
10:52And we're going to set the className back to required, and we'll look at why in a minute.
10:59We have written the loop to do that part of it. What we need to do now is pass
11:04in the final argument to the addEventHandler, which is false, and that part is
11:11now done. So now we have written an event handler for the reset, and the reset
11:15is going to put the focus back into the first input field and reset all the
11:19labels in case doing that red state back to being black by changing the CSS class.
11:23What we need to do now is add an event handler for the Submit event. So
11:28let's do that. We'll say com_joemarini. EVENTS.addEventHandler and we'll add it
11:35on the form again. So we'll just copy and paste the code from here and
11:44the event this time is submit and on the submit, we want to call
11:50the validateAllFields function and I'm passing false for the capture argument.
11:57So now we have setup the reset and event handlers. Now, we need to add the
12:02default focus handler. This is when the page first loads. Remember this whole
12:07function initFormElements is being called when the window loads. We want to set
12:11the focus to the first form field, and we already have code that does that
12:16right here. So, let's go ahead and copy that and just paste it down here. So
12:22we have written our part, and now we need to add the event handlers for
12:25validation, but we'll come back and take a look at that. So let's go ahead now
12:30and run this example in the browser. Okay, so here we are running the document
12:35in the browser now and you can see that we have written the event handlers for
12:40the focus and the blur events. So we are getting the focus changing, and you
12:45see the styles are all changing, and the highlight is changing on the form
12:48fields, but what's not happening is the validation. These fields aren't
12:52changing to red when I'm changing the focus. So let's go back and fix that.
12:57So I'm back in the code and what we are going to do is add event handlers for,
13:02well, specifically the blur event. So when the field loses focus, we want to
13:07validate the field. So I'm going to copy this right here and I'm going to add
13:12an event handler and the event handler is going to be on the Subject, Address
13:18and Message fields. So we are going to say document.forms, 0, .subject.
13:31And we're going to put it on the blur event
13:34and we're going to say validateSubject. And we are going to do this three times, one for each
13:43of those fields. So there is the Subject, there is the Address field, and there
13:49is the Message field. And these are all named elements in the form; you can go
13:54back and take a look at that. And we are going to validate the Address, and
14:00validate the Message. So now let's go back and take a look at the updated code
14:07in the browser. Okay, so now you can see that as we change the focus from the fields,
14:14the validation is taking place. So now let's go back to the code and
14:18take a deeper look at what's going on under the covers. Starting with the
14:24highlight and unhighlightFormElement functions, those guys are right here. So
14:30what's happening here is inside the code for highlighting the form element,
14:34I'm getting the event target, which is going to be the form field, and I'm setting
14:38the inline style to those strings that we have up at the top for what the style
14:43should look like when it has the focus, and I'm taking it off when it should
14:47not have the focus. Now you might be wondering, gosh, isn't using inline style
14:51is not a good thing to do? My personal opinion is that, it is not a good thing
14:55to do when you do it in the markup, but when you are doing it in code like this,
14:58you are not actually marking up your HTML markup with inline styles.
15:02This is just a temporary application of an inline style, and in fact, the reason why
15:07you want to do it like this is because inline styles override whatever class
15:11you have defined for that element. So when you take off the inline style,
15:15it just defaults back to being whatever the class definition for that element is.
15:19So this is a pretty efficient way of just applying a temporary look and feel to
15:24a form element.
15:26So here we are applying the look and feel and then in unhighlightFormElement,
15:29we are just taking it off. We are setting the border back to being the
15:31unfocused style and changing the background color to be nothing, in which case
15:36the overriding class we defined in CSS takes over. Okay, so let's go back up
15:42here and look at some of these other things that we have done. So for
15:45validation, you can see that on the submit, we have a function here called
15:50validateAllFields and we also have some other validation going on in these
15:53functions here. Let's take a look at those. I'm going to scroll down to these guys.
15:57So let's just take a look at one of them and you'll get a sense of
16:00what's going on. For the validateAddress, it's very similar to validating the Subject,
16:05but it uses a regular expression. So I want to focus on this one. So,
16:09what we do is we get the document. GetElementById, we get the address out of
16:12the form and we have a local variable named ok, which is checking to see if
16:18the length of the field is not equal to zero, and here we have that regular
16:22expression and we are calling the test function on the regular expression with
16:28the value of the form field. So, let's go back up and take a look at that
16:32regular expression. So here is the regular expression that validates the Email
16:35Address. You can see that it starts with the beginning of the value in the form field,
16:39and then looks for anything that might be present in an email address.
16:44So we have got word characters, we have got non-space characters, equals, dashes.
16:48The plus sign means it's got to be at least one of those, possibly more.
16:52That's followed by a literal @ symbol and then followed by a whole bunch
16:57of characters that indicate the domain, followed by a period and then a whole
17:02bunch of characters between 2 and 4 that are either .net, .info, .com, whatever,
17:08followed by the end of input. So that's the regular expression that validates
17:13the email and the result of this function is returned as a Boolean variable.
17:19So if it doesn't validate, this value is going to be false, and if it is false,
17:23we change the class name to invalid. Otherwise we change it to validated. So,
17:30let's take a quick look at the CSS code for this. So here we have the CSS code
17:36for the form and you can see that on the label, I have got a bunch of classes
17:41defined. Right here, you can see a little trick I'm using to get the pointer
17:45hand to appear both in Firefox and in IE. IE doesn't understand the hand value.
17:52So I'm going to trick it by using pointer. This is a cross-browser way of
17:55getting the pointy hand to work in both Firefox and IE. And you can see here,
17:58I have got a required and a validated and an invalidated subclass. So for invalid fields,
18:04we have got the color changing to red and the color changing to black
18:07if it is validated, and the required class, just no color at all. Just Bold.
18:11Okay, let's go back to the form.
18:14So the story is pretty much the same for the rest of the validation functions.
18:18This function here validateAllFields gets called when the form goes to get
18:22submitted. So all we are doing here is having a Boolean variable and what we
18:26are doing here is checking the return value from each one of the validation
18:29functions, and if everything passes, then we are fine. Otherwise we show an
18:34alert which says hey, the fields marked Bold, you're required to go back and fix it,
18:39 and then we call the utility function that I have written called
18:42preventDefault. This will prevent the Submit event from going through to the browser.
18:47Okay, well, that's pretty much all there is to it. Now you have a
18:51working example of how you can improve the interactivity and usability of your
18:56forms in your pages.
Collapse this transcript
Seeing if a window is already open
00:00In this example, we are going to see how to solve a common JavaScript
00:03programming problem and that is how to tell if a window that has been opened by
00:08another window is already open, so that we can prevent it from being refreshed
00:12if the user clicks a link or takes some other action that causes the window to
00:16be open again. So you'll see this in situations where we pop-up a window to
00:20have the user fill out some information and for some reason, they go back to
00:24the main window, click the link or something, and then the window you open refreshes.
00:28So we are going to fix that problem. So let's try this out.
00:30I have the document here open in the browser and the behavior that I'm looking
00:34for is that when I click this link, the window will open and if I click it
00:38again, if the window is already open, it won't refresh, it will just come to
00:41the front and be active. So let me click this. You can see that when I click it
00:46the window opens.
00:47Now I'm going to go back to my browser and click it again and now the existing
00:50window should just come right to the front and you can see that's what happens.
00:53Okay, so let's take a look at the code to see how we solve this problem.
00:58Okay, so here I'm in the code and before we begin looking at the solution,
01:03let's take a look at some of the code that's already written here. So down here
01:07at the bottom of this script block, I have included my cross-browser event
01:12handling code, right here, you can see that's here, this script tag.
01:16Down here, I'm adding an event handler for the windows loadEvent. So when the
01:21window loads, the loadHandler function is going to get called. And in the
01:26loadHandler, we have another event registration. In this case, we are
01:30registering the click event on that link and it happens to have the ID of
01:35opener attached to it and that function is going to be called openwindow.
01:41So the openwindow function, which is the event handler for the link, is going
01:45to do a couple of things. First it's going to assign the result of myOpenWindow
01:51to this global variable and it calls myOpenWindow with some parameters and the
01:56parameters are the window we want opened along with some properties that the
02:00window.open function in JavaScript needs and we are also going to pass in the
02:04global variable gmywin. gmywin starts out as null. I've got it declared up here.
02:11The function we need to write is this one right here myOpenWindow. We are going
02:13to start off, declare a little temporary variable, var theWin.
02:19What we need to do is first check to see if the window that we opened already exists because
02:25if it does, we don't want to open it again. We just want to activate it and give it the focus.
02:29So I'm going to write if (winObj != null), then event takes an action and
02:38winObj was passed in here. Recall this is the global variable that we passed in
02:42from the calling function down here.
02:47So if it's not equal to null, now we need to check if the user closed it and
02:52windows have a property called closed on that we can check. So we'll write if
02:56not winObj.closed, okay. So that means it's been created and it hasn't been
03:03closed yet. So now we are going to write winObj.focus. This will bring the
03:10window to the front and give it the input focus. We'll just write return
03:16winObj() at this point.
03:18If window object is equal to null or if it's not equal to null and it's been closed,
03:23that means we have to reopen it. So we are going to fall through to the
03:27code down here and we'll write theWin = window.open() and window.open takes the
03:37parameters that we passed into myOpenWindows. So we'll just pass those through.
03:41There is winURL, winName and winFeatures and then just return theWin from this function.
03:52So, we should be ready to test this out now. First, I'm going to save it and
03:57going to view it with Firefox. Okay, here we are and then click Open New Window
04:04and there it is. And I'm going to go back to my main window, click it again and
04:08look here there it is. Activates. Very nice, okay.
04:11Now let's try it out in Internet Explorer to make sure that that's working
04:14correctly as well. So let's go ahead and View in Browser. There is the window,
04:22we click, up comes the window, we'll go back to the main one, we'll click it,
04:27and it works just fine.
04:29So, now you know how to check to see if windows have already been opened and
04:31how to activate them. So let's move on to our next example.
Collapse this transcript
Using information already in the page
00:00In this example, we'll see how we can use information that's already in the
00:04page combined with some JavaScript to provide some automatic behavior for us
00:09that increases the user's ability to consume that information.
00:14So here I have a window open in the browser and you can see I've got a list of
00:20links in here. Now some of these links go to HTML files but some of them go to
00:25PDF files. The problem is I can't tell which ones are which without mousing
00:30over each one of the links and I've also got a link here that's just a named anchor.
00:34Now it sure would be nice if I had some automatic behavior that I could just
00:38drop into my web pages that would somehow automatically indicate when a link
00:43that I'm looking at points to something other than a PDF file. So let's see if
00:47there is a way we can fix that problem.
00:49We are going to switch over to the code now. So here I have my document open in
00:53the design surface and what I'm going to do really quickly is jump over to the
00:58JavaScript code and I'm going to show you the result and then we'll go back and
01:03see how it works, so I'm going to uncomment that line and save it and then I'm
01:07going to switch back over to the browser. Okay, now I'm going to refresh this
01:10page and you can see while I refresh the page, some behavior automatically
01:15happened. You can see that these two links right here are decorated with these
01:19little PDF icons.
01:20Now I can see easily which links go to HTML files, which ones don't. So let's
01:25take a look at how we accomplish that, switch back over to the code, so here we
01:30are back in the code now, what I'm going to do is switch to the Source view of
01:35the document and a couple of things I'm going to point out first, here is my
01:39cross-browser event handling code that I wrote and there is the JavaScript for
01:44the automatic icons.
01:46Now one of the things that I want to point out is that there is nothing in this
01:49file anywhere that has any inline events or anything like that being assigned;
01:53all of that is handled via the automatic JavaScript event handling loading that
01:59I have got in my Event library. So I have separated the behavior out from the
02:03content and here are the links, you can see that some of the links are HTML,
02:07some are PDF, here's a Named Anchor. So what we want to have happen is for each
02:12one of these links that has a PDF ending, we want to have that image appended
02:17after it, so that we can tell that it's a PDF link.
02:20So let's go over to the JavaScript code to see how that works. Here is the
02:24JavaScript code and right down here at the bottom of the file, you can see
02:28I have got an event handler for the windows load function and when the window loads,
02:32I'm going to call a function named insertLinkIcons. That's this function right here.
02:40Let's take a look at how insertLinkIcons works. What we need to do first is get
02:45an array of all the link tags in the document and we are going to do that by
02:49using the standard DOM function getElementsByTagName. This will return array of
02:54all the links in the document. Let me store aside the number of links that are
02:58in that array, with this count variable right here.
03:01So now we need to loop over each one of these link tags and get the href
03:05attribute and see if it ends with the .pdf. So in this loop, we'll loop over
03:11all the links and we have a temporary string that sets aside the value of the
03:17getAttribute call, which is again the standard DOM function for each one of the
03:20links, and we are getting the href attribute.
03:23Now I should point out this particular test only checks for links that end with
03:27.pdf. You could modify this file to check for other things, like Word files or
03:33PowerPoint or Excel or anything like that. What I'm doing here is checking to
03:37see if the string has a lastIndexOf the PDF that's not equal to -1. So the
03:44lastIndex function is a standard string function and it looks for this string
03:47and returns the character position that that string is located at. And if it
03:52returns -1, then it wasn't found.
03:54So if we did find the .pdf, what we now need to do is create that image element
04:00on the fly using the DOM and set its attribute to the source of our image and
04:06then put it into the document after the link. So that's what we do here. This
04:11variable image we call document. createElement, it's a standard DOM function and
04:15we are going to create an image tag and then we are going to set a couple of
04:18attributes. We are going to set the source attribute to be the path to the icon
04:22we want to use and you can replace this with whatever path happens to go to
04:26your images directory. Then we set the alignment attribute to the absolute
04:30bottom. This just helps us line up the icon with the text a little bit better.
04:35So now that we have created the image, we need to insert it into the document
04:38after the link tag. You can see here I've got aLinks sub i. This is where in the loop
04:44I'm telling the parentNode of the link, whatever it happens to be, to add
04:48a new child using appendChild. This is a standard DOM function where appending
04:53the image tag we just created after the links object that we are working on.
04:58Now I could modify this. Instead of saying appendChild I could write
05:02insertBefore, which is also a standard DOM function, and if I do this and then
05:08I save, I'm going to go back to the browser and refresh it.
05:11Now I'm going to refresh, you can see now that the icons are appearing before
05:19the links instead afterwards. Okay, let's go back to the code.
05:22That's all there is to it.
05:23So now we have seen in this example how to use the DOM and examine some
05:27information in the page to provide a better experience but we can get even
05:31better than this. Let's take a look at another example.
05:34So this is another example, what we are going to do in this case though is
05:37create an automatic set of bookmarks or like a mini table of contents at the
05:42top of the page and you can see I have got this long document here, I have got
05:46a whole bunch of information, I have got some subheadings and so on. So let's
05:52look at this document in the browser and see what happens.
05:59So here we are in the browser and you can see that this set of links has been
06:03automatically generated for us because you can see it's not here in the source
06:07document but right above the introduction, somehow this list of links got
06:12generated. So let's go take a look at the code to see how we solve that problem.
06:16Let's look at the source and return to the top here. Again, I have got my
06:24cross-browser events loaded here in the source and here I'm handling the window
06:30load event and in this case, I'm passing the function named buildBookmarks and
06:35it takes a couple of parameters. This one is an h3 tag and something named Header.
06:40So the first thing I want to point out is that value header right there is the
06:44name of this div's Id attribute. So that's going to become important in a
06:50moment, let's see why? The h3 that I'm passing in, you probably guess that's
06:56corresponding to H3 tags and you can see that each one of the section headings
06:59is an h3 tag.
07:00So let's take a look at the JavaScript code to see what buildBookmarks is
07:04doing. So this is the function buildBookmarks, which is being called, and you
07:09can see that it takes two parameters. This is the which tag to build the
07:13bookmarks for and that's the h3 we passed in. And we give it the name of the
07:17div that we want to have the bookmarks inserted into. We've got a global
07:21variable up here called g_cAnchorCount and we'll see what that does in a moment.
07:25So, the function starts off by setting the g_cAnchorCount to zero. Now what we
07:28are going to do is create the unordered list that's going to hold the bookmark
07:31links. So we do that using the DOM, we call the Create Element standard DOM
07:35function for creating the unordered list that will hold the links, and we set
07:39its Id attribute to Bookmarks list.
07:42What we need to do now is get a list of all the elements in the page that we
07:47want to make bookmarks for and typically these will be heading tags and indeed
07:51in this example, we passed in an h3. So this call right here,
07:55document.getElementsByTagName on the strWhichTag variable that we passed in the
08:01parameter, it's going to return an array of all the h3s in the document.
08:05So now we have a loop that goes through all of the h3 tags and is going to make
08:09a link and a list item for each one of those guys.
08:13So to get the content inside the h3, what we do is for each one of the h3s we
08:19use the standard DOM property firstChild because the text inside of the h3 tag
08:25is considered its own node in DOM. So this gets us to the text node, the
08:30firstChild, and then text nodes have a property called data on them, which
08:34returns the textual data that's inside that text. So this will give us the text
08:39that's inside the h3.
08:40Now we need to build a Named Anchor for that location because we are going to
08:44insert a named anchor in front of each of the h3s that we want to jump to when
08:49the user clicks those links. I have a small Utility function named
08:53buildNamedAnchor right here. Let's quickly jump down and take a look at that.
08:57buildNamedAnchor essentially returns a string in the form of a named anchor, so
09:03we have the A tag and the name is bookmark and the AnchorCount is a number that
09:08we append onto the word Bookmark. This is what ensures that each one of the
09:12named anchors is going to be unique in the document.
09:14The reason I'm doing it this way instead of using the DOM is because there is a
09:17bug in IE when creating Named Anchors with the Create Element function in the
09:22DOM. So buildNamedAnchor will return with the Anchor tag. Now what we need to
09:30do is set the innerHTML of the h3 tag that we are working on to be the HTML for
09:36the Named Anchor along with the existing innerHTML for that h3 tag and what we
09:44are doing here is we are using the DOM property innerHTML, it's not a standard
09:50as far as the W3C is concerned but all the modern browsers support it.
09:54IE supports it, Firefox supports it, Safari supports it, this will work in modern
09:58browsers. So now we have got the h3 content, plus the Named Anchor in front of it.
10:04Once we have done that, we've to go back and create a list item for the link
10:08that's going to be in the list at the top of the page and we used the DOM for
10:11that. We create the list item element right here and then we create an anchor
10:15tag or a link tag to go inside of it.
10:17Now we are going to set the link destination to be the Named Anchor for the
10:21bookmark and remember we have got the anchor count here which is the number of
10:26the named anchor and then we just set the href attribute for that link to be
10:32the Named Anchor link destination we created in this line right here.
10:36Now we have had that created, we need to add that link to the list item. So the
10:40list item, we call the DOM function appendChild that add the link into it.
10:45Now we have to create a text that's going to go inside the link. So using the DOM
10:50function, create text node for the string Name variable and remember sName got
10:55setup here. We stored that aside. This was the text that's inside the h3 tag.
11:00So we store that aside. That's going to be the same content as the link that we
11:05are creating for the list.
11:06So we append that into the link and then we add the entire finished list item
11:11into the unordered list, right here using appendChild. Now that we have done
11:15that, we increase the AnchorCount so that that way the next named anchor will
11:18be unique and then this loop will go over all of those h3 tags. When we are
11:22done, we call this function here called insertBookmarkList and it takes the
11:27list we just built and the bookmark node in the DOM tree where we want to add it.
11:33That's this function right here. It's very short. All we are doing is getting
11:36the element by Id of the bookmark node and remember that was the Id of the div
11:41that we want to have the bookmark list inserted into. So all we need to do is
11:45get that element and then tell the list destination, in this case the list
11:49host, to append the bookmark list into the end of its existing content. So this
11:54will add our bookmark list at the end of that div indicated by this Id that
11:59we passed in.
12:01So let's go look this in the browser, go back to the HTML and I'm going to
12:05choose Browse with Firefox, so you can see that the list was automatically
12:11created and you can see that the content of each one of the H3s is now the
12:15content to each one of the links.
12:16All right, so here you can see this text got inserted up here and now when I
12:20click the links, it's jumping to the Named Anchor that we built on the fly and
12:25inserted in front of that h3 tag and I can do that with each one of these guys,
12:29go back to the top, click on this guy, back to the top, click on this one.
12:35So it works in Firefox, let's make sure it works in IE. Yeah, looking it's
12:43working just fine. Okay, so now you have everything you need to know, to see
12:47how to extract information that you have already got in your page to add some
12:50better usability and interactivity to your web pages using JavaScript.
Collapse this transcript
Improving tables
00:00So now it's time to have some fun with tables. Tables are really great for
00:04displaying tabular data and you can see I have got a sample table here in the
00:09browser and showing some stock activity for a certain date range, and if I scroll through,
00:16you can see that one of the things that jumps out right away is that
00:19it's kind of hard to read this information.
00:22One of the ways that you can make tables more readable is to have the table be
00:28striped using alternating colors. So for example, you stripe this row with one
00:32color, this row with another color and so on, you alternate the two rows.
00:36So there is a way in JavaScript that you can have this automatically happen in
00:40your documents. So let's see how we can do that. This is the HTML file for the
00:46document I just showed you. You can see right up here, this is the table with
00:51all the content in it and so we have a head section for the table, those are
00:55the column headers, and then down here we have the table body.
00:58Now, before we dive into the code, I'm going to just quickly show you what the
01:02effect is. So I'm going to uncomment this line, and save it, and then I'm going
01:07to go back to the browser and refresh.
01:11So here we are back in the browser. Now watch what happens when I refresh the
01:14window. You can see that what happened was the table automatically became
01:19striped with alternating row colors. Now, this is a much easier to read
01:24example, because the human eye just naturally follows the band of color across the line.
01:29Let's see how we did this using some JavaScript and CSS. I'm going to go back
01:33to the code. So let me scroll to the top here. You can see that I have done a
01:38couple of things. First I've included my cross-browser event handling code
01:42right here, and then I have got two other JavaScript files that I have included
01:47and we'll get to the highlight tables example in a bit, but first let's take a
01:51look at the table stripe.jscode. So let me get over to that code. All right,
01:56this is the code and you can see that it's very short, it's only a couple of
01:59dozen lines of JavaScript and that's including all the comments.
02:02So down here at the bottom, I'm adding an event handler for the windows Load
02:06event and I'm passing in a function that's going to call a function named
02:10createStripedTable, and that function createStripedTable takes an array.
02:15In this case, it's an array of table IDs that you want to have automatically
02:19striped. So you can pass in an array containing the IDs of the tables you do
02:25want striped and leave out the tables you don't want striped and so on. So all
02:29the magic happens right here in this function named createStripedtable, and
02:34there is the parameter that takes the array of tables we want striped.
02:38The way that this works is we loop over each table ID that we're given and we
02:42stripe all the rows using CSS styles. So I have a variable here, index, and
02:48it's going to loop over the length of this array and in each one of the array
02:52indexes, we have the ID of the table we want to stripe. So we start off by
02:57using the DOM function getElementById to retrieve the table that is given by
03:02that ID. Now, if for some reason, a bad ID was passed in, we check for null and
03:06we don't stripe that table.
03:08Assuming we got the table okay, what we need to do is get the table body
03:11because we don't want to stripe the head. What we want to do is stripe the contents.
03:14So we call getElementsByTagName on the table body and we loop over
03:20the table body's length because the table body has a whole bunch of tr tags in it.
03:25So we get an array of all the TR tags in the body, by again calling
03:30getElementsByTagName. This time on the body not on the document or the table,
03:34and we ask for all the TR tags.
03:37Once we have an array of all the TR tags, it's just a simple matter of looping
03:41over each table row tag and sending its class name based upon whether this
03:46variable here, the loop variable is divisible by 2 or not. So for alternating
03:51rows, we are going to apply the stripe2 CSS class or the stripe1 CSS class.
03:58That's pretty much all there is to it.
04:00Now, using this function, you can drop this into any one of your documents,
04:04pass it an array of table IDs, and they will automatically be striped for you.
04:09In fact, we can just get fancy, and we can change this guy to stripe1, and this
04:14guy to stripe2, and now I'll go back over to the browser and see what the
04:18effect is. I'm going to refresh, and you can see that basically the stripes
04:24just traded places. Let's get a little bit fancier, and go back to the code.
04:28Now, I'm going to uncomment a different line in a different file and let's see
04:33what effect that has. So I'm going to uncomment this guy right here. All right,
04:39let's go back over to the browser. We are back in the browser. I'm going to
04:42refresh. So it doesn't look like anything happened, but watch this. Now,
04:47when I mouse over the table, you can see that as I move the mouse over each individual row,
04:52it's highlighting that row making it even easier and more attractive for me to read.
04:57In fact, I can click on a row, which will freeze that highlight right there.
05:02I can move to a different row, click on that one, you can see that what I'm
05:05essentially doing is moving the highlight around in order to highlight an
05:08individual table row. If I click on a row that's already highlighted, I just
05:12turn the highlight off. Okay, that's pretty cool. Let's take a look at how
05:15we did this in the code.
05:17So to achieve this effect, again I'm adding an event handler on the windows
05:22load event, and in this case, I'm calling a function named
05:25createAutoHiliteTableRows and again, I'm passing an array of table IDs and
05:31that's this function right here. So I have got a global variable that keeps
05:36track of the current table row, and this is the variable that's going to keep
05:40track of which row is currently highlighted when a user clicks on it. So we'll
05:43get to that in a moment.
05:44All right, very similar to the previous example. Here, we are checking to see
05:50if we have a DOM capable browser, I added this just to be illustrative of how
05:54to check to see if your browser has the DOM in it. Most modern browsers do
05:57these days, some mobile browsers don't. So I might want to leave this check in.
06:02So similar to the last example, we have a loop over the array of IDs we were
06:06given, and we are going to get each one of the tables that we want to have this
06:09effect applied to. So we call getElementById with the table ID and if it's
06:14null, we just skip all this.
06:16So what we are going to do now is ask the table for all of the TR tags. Similar
06:21to the last example, what we are going to do is for each one of the TR tags in
06:25the array, we are going to loop over each one of those. Now, we only want to
06:28highlight those table rows that are children of the T body. We want to exclude
06:32the T head from this. Now, if you want to highlight every row, you can just
06:36take this test out. But I'm leaving it in for now just to highlight the ones in the body.
06:41The way this works is we add event handlers for each one of the table rows to
06:46handle the mouseover and mousedown events as well as the mouseout event. So for
06:52each one of these events, we need to set the style of the table row to be
06:56highlighted when the mouse moves over it appropriately. So the mouseover event,
07:02I'm assigning a function here, an anonymous function.
07:05So one of the first thing to do is to check to see if the current table row is
07:10equal to this table row, and the reason for that is because if you noticed in
07:13the previous example, when I moved the mouse over the table row that have been
07:16clicked on, the highlight didn't apply. So in this case, I just return false,
07:19so that the highlighting doesn't take effect. Otherwise, I set the inline
07:24background color and font weight of the table row to be bold and this color
07:29right here which is sort of that yellowish orangish color.
07:32Now, you might be saying to yourself, hey! Wait a minute, I thought I wasn't
07:35supposed to use inline styles, I thought that was a bad practice. Well, it is a
07:38bad practice if you do it in your markup. Since we are doing this in an
07:42ephemeral fashion in script code, my personal opinion is that not only this is
07:47an okay way to do it; it's actually a pretty good way to do it. And the reason
07:50for that is because inline styles will take precedence over any class that you
07:54may have assigned to your table.
07:56So if you've pre-styled your table using some type of CSS styles, this will
08:00only temporarily override all of the classes that you have applied to it. If we
08:06didn't do it this way, we would have to remember which class was assigned to
08:10the table, temporarily save it aside or the table rows, and then put it back
08:14again when we were done. All this does is temporarily override the class.
08:18On the onmouseout function, we just simply take those inline styles off and that
08:22returns it to its default appearance based upon whatever classes you have defined.
08:26Now, the mousedown function works a little bit differently. In the mousedown
08:30function, we have to check to see if there is already another row highlighted,
08:33because we first have to un-highlight the current row before we move to the
08:37next one. So if the current TR global is not equal to null,
08:41that means we have a row that's already been clicked on and is
08:44currently highlighted.
08:45So we need to take off the background color and the font weight that we
08:48applied, and then set the value of the current row that was clicked on to this
08:53table row. If it's already equal to this table row, we set current table row to
08:58null. That's how we remove the highlighting from all of the table rows or the
09:01one that was already highlighted, and we simply return.
09:04Otherwise, we remember that this was the row that was clicked on; we set that
09:08into the current table row and we highlight it using that kind of bluish color with bold.
09:13Now, you might also be saying to yourself, hey, wait a second. I thought I
09:16wasn't supposed to use these on event properties. I thought I supposed to use
09:21the new DOM level 2 and new IE event model functions, you are. The reason I did
09:28it this way was because it turns out that in all browsers except for IE, that
09:34this keyword is held properly. So in IE, the This keyword loses its meaning
09:40when you move inside of an onmouseover function using the New Level 2 events.
09:46It refers to the global window object.
09:48Now, this is not standard behavior defined anywhere, but all the other browsers
09:52like Firefox and Safari and so on, they automatically set the value of the This
09:56keyword to be the element that the event happened on. IE doesn't behave like
10:02that, so we have to default using the mouse properties like you see here.
10:06So that's pretty much all there is to it. Now, you have seen how to improve the
10:10interactivity and usability of your tables using some JavaScript and CSS code.
Collapse this transcript
Sorting data in tables and lists
00:00So in this example, we are going to continue our tables theme by looking at how
00:04you can sort information in a table right in the browser. Now, we are going to
00:08go back and take a look at an example we looked at earlier during the course.
00:12This was the example I used during the Progressive Enhancement lesson. During
00:17that lesson, I didn't really focus on the sorting part of it, I just focused on
00:21the way that you can use progressive enhancement in the page. So I'm going to
00:25go back now and take a look at the actual sorting algorithm to see how we do
00:29that in the page using the DOM.
00:31So recalled from the previous lesson, by clicking on these arrows, the user was
00:36able to sort the content of the table right in the browser. So we are going to
00:40take a look at how that code was written and we are going to write on the fly
00:43this time, you are going to follow along with me and we'll try out the end result.
00:47So let's switch over to the JavaScript code. Let's scroll down to the bottom
00:53first and remember I'm using my Cross Browser event handling library here. So
01:00I'm adding an event for in window Loads. We are going to call a function called
01:04insertSortControls.
01:06The insertSortControls, that's this function here. Now, if you watch the
01:12previous lesson on progressive enhancement, this will just be review, but what
01:16we are essentially doing here in the insertSortControls function is getting the
01:21item descend, ascend, PriceDescend, and PriceAscend elements. If we look at the
01:26source code for the HTML, those are these guys right here, these links. Inside
01:31the links, we have these images. So we are going to get references to each one
01:36of these links in the JavaScript code.
01:39We are going to remove the Href attribute, and we are going to add a
01:43cross-browser event handler for handling the click events. When the user clicks
01:48these arrows, we are going to call the function sortTable with a variety of
01:52parameters indicating how we want to sort the data. So that's what we are going
01:56to focus on is how the data in the table gets sorted.
02:02So that's this function here, sortTable. The parameters that get passed to
02:06sortTable are which table, which column, and the sort direction. The whichTable
02:13parameter indicates the ID of the table that we want to be sorted. The whichCol
02:19parameter indicates which column in the table we are sorting on, and the
02:23sortDer parameter tells us which direction we are sorting in, whether it's
02:28ascending or descending.
02:30So we start off on this line here by using the DOM's getElementById function to
02:35get the table for which the ID we were given. Once we have the table. We begin
02:41by getting all of the nodes for the table body. Now, tables can contain more
02:45than one table body. So this code here asks the table to get all the elements
02:51by tag name and that's the T body and we are just going to take the first one
02:54in case the table has more than one T body in it. That's not common,
02:58but it is possible.
03:00Once we have the table body, we are going to get all the table rows. The reason
03:04we are doing this is because the rows are what's going to end up getting
03:07sorted. We'll see how that's done in a moment. What we are going to do here is
03:11store aside the number of rows that are in the rows array. So this comes back
03:18with an array of table rows, and we'll just look at the length we have stored
03:20at the side.
03:21Now, we have a couple of global variables, and the reason we are using global
03:24variables here is because we have a callback function that JavaScript is going
03:28to call when the user is sorting. So we store aside whether or not we are
03:34ascending or descending from the sortDirection parameter, and we also store
03:38aside the column in the table that we are sorting on.
03:42The way we are going to do this is we are going to make a temporary array. Then
03:45the array is going to hold each table row tag that's in the body, and this is
03:49the array that is going to be sorted.
03:52We are going to do this outside of the DOM, because what we want to do is sort
03:56the data. So that when the data is being sorted, the user is not getting a
04:01whole bunch of flashing and flickering in the browser. Remember, one of the
04:05attendants I talked about earlier in the course was, when you are making
04:08changes to the DOM, do it in memory and not right in the page. That way a, it's
04:12faster and b, the user is not getting all this flickering action.
04:16So we are going to make a new array, and it's going to be the size of the
04:20number of rows we stored aside earlier and this is going to be the rows that
04:24are going to be sorted. So what we'll do now is copy each one of the TR tags
04:28that we have from the table body into the array, and we are going to do that by
04:32using the standard DOM function cloneNode.
04:35Now, cloneNode takes a parameter of true or false, and that indicates whether
04:39you want to do what's known as a deep clone. If I were to pass just False here,
04:44that would mean just make a copy of the table row tag by itself.
04:49By passing the True parameter, it means make a copy of the current element I'm
04:54making a copy of, plus all the child elements underneath it. We want to do that
04:58here, because we need to make sure that all of the TD tags which contain the
05:02data come along with the table row, and we'll see why later. Now that we have
05:07done that, we just use the sort function for sorting the array and we pass the
05:13sortCallBack function, which is what does the sorting.
05:17We are going to break here and go up to the sortCallBack function, because
05:22that's where all the magic happens and that's this guy right here. So the code
05:26that we have to write is going to take the arguments that are passed to the
05:29sortCallBack function and recall earlier I talked about how the sortCallBack
05:34function works on the array object.
05:36JavaScript is going to call back into this function and give us two arguments,
05:38a and b. The job of the sortCallBack function is to determine which one of
05:43these two guys is bigger, which one should come first? That's how the sorting gets done.
05:48So what we need to do is look at the data for the column in the table that we
05:52are sorting on and then figure out which table row needs to come first. That's
05:56the body of this function, and that's the code that we are going to write now.
06:00So what we need to do is to find a couple of local variables. We are going to
06:09say var col1 = a, and remember, when it gets passed in, this is a table row. So
06:12we are going to say a.getElementsByTagName and we want all of the TDs that are
06:24in the table row, and remember we stored aside the column that we were sorting
06:28on. So we get all the TDs and that we index into that by the global variable of
06:34the column that we were sorting on.
06:37So that gets the first table column whose data we need to look at. We need to
06:42do the same thing for the second column. So the second column, this time it's
06:46just going to be b's elements. So now we have got the TD tag for the column
06:52that we're sorting on.
06:53Now that we have the column, we need to get the text data out of the column. So
06:59let's create a couple of more variables, say var text1 = col1. That's the TD.
07:06Now, we use the DOM property, firstChild. That steps down to the text node
07:12that's inside the TD tag and then we use the data property, which gets us the
07:17text data out of the text node. We have to do that again for the column 2. So
07:24we'll call that text2 and col2.
07:27So now, we have the text data for the column that we are sorting on inside the
07:32TD. Now, this may seem a little bit abstract, and it might be helpful to have a
07:38diagram of what's going on here. So let me switch over to a diagram, so you can
07:42better understand what this is going to look like.
07:45So to understand what's happening here, we've built an array. Remember, we had
07:49that array where we stored a number of rows, and then we copied the TR tags
07:52into each one. So each one of these slots in the array, however many there are,
07:560 to end, each one of those guys is going to be holding a table row tag.
08:02Remember, each table row has a series of TD tags underneath it.
08:07Now, what we are doing here is suppose that this is the column that we are
08:10sorting on, column number 2 right there. What we are doing is we have to get
08:14the data out of that column, but it's the table row itself that's going to be
08:18sorted. So this is what the contents of the array that we are sorting looks like.
08:24So our code is extracting the text data that's inside the column referred to
08:29here by that down arrow, and is going to cause the table row itself to be
08:33sorted into the right place. So when the sortCallBack function completes, all
08:38of the table rows will now be in the proper order based upon the content of the
08:43column that we were sorting on.
08:45So let's switch back over to the code and complete our example. At this point
08:50right here, we now have the text for each one of the columns. So now what we
08:53have to do is figure out which one comes first, and we have some simple
08:58arithmetic going on here. We simply return, if text1 should come before text2,
09:03then based upon whether we are ascending, remember this function returns less
09:08than 0 if a should come before b. It returns greater than 0 if b should come
09:13before a, or it returns 0 if they are both the same thing.
09:17So in this case, if we are ascending, we want to return whether A should come
09:21first or A should come second. Similarly, if it returns out that ordinarily, B
09:26would come next, we have to check the ascending value to see if A should really
09:30come first or B should really come first. If the two are the same, then we just return 0.
09:35Let's go back down to the code and sort table. So after this function comes
09:39back, now the array has been sorted, and we basically put back all the table
09:44rows that we copied out earlier. So the way we do that is by building a new
09:48table body with all the table rows that are sorted in place.
09:52So we use the DOM function removeChild to tell the table to get rid of the
09:58existing table body that we have the reference to. Then we make a new one in
10:02its place using the createElement function. So we create a new table body.
10:06We add that table body into the table using the appendChild function and once the
10:11table body is in there, we now loop through all of the contents of the sorted
10:16array and copy back in all of the table rows that have now been sorted based on
10:22the contents of the column that we sorted on.
10:25That's pretty much all there is to it. So we have written the code. Let's go
10:31browse this in the browser and see what happens. Browse this in Firefox.
10:39So here we have the arrows and you can see that as I'm clicking, here we are
10:43sorting on column 0, and we are doing ascending and descending, and the same
10:49thing works for price.
10:53So now you have seen how to use the DOM and JavaScript to sort data right there
10:58in the browser. Let's move on now to our next and final table example.
Collapse this transcript
Using paginated tables
00:00So for our last example involving tables, I'm going to show how you can take
00:05tables and make them a little bit easier to consume, especially when they get pretty large.
00:10So here we have a table full of Stock data, and it's similar to the example
00:14I showed before, where we did highlighting and striping. Only in this case,
00:18you notice the table is kind of big, it sure would be nice if I had some easier way
00:22of maybe breaking this table up into smaller chunks or pages that I can consume more easily.
00:29So let me go to the code for a second and show you what we're going to do.
00:32I'll show you the effect first and then we'll look at the code to see how it works.
00:36So I'm going to close this window.
00:38What I'm going to do is uncomment this line of code right here and uncomment
00:43this and now I'm going to go back to the browser. So here we're back in the
00:48browser. You can see that what happened was the table has now become a lot
00:52shorter and we have these first and previous and next and last page controls.
00:57So if I click say on next page, you will see that the table automatically
01:01advances to the next page of data. I can keep on doing this. I can click last
01:06page and first page, and I can advance and go back through the data.
01:11So what I have essentially done is taken this table of data and broken it up
01:17into individually consumable pages or chunks.
01:22So let's look at the code to see how this works. Let me point out a couple of
01:26things. The first thing I want to point out is here is my cross-browser event
01:32library and I'm adding a window load event handler for a function that's going
01:38to be called createPagedTable, and we'll see how that works in a second.
01:44So createPagedTable, one of the things I want to point out here is its using an
01:48object that I created called pagedTable and we're assigning that to a global
01:53variable called gThePagedTable.
01:56We also add some enter handlers. These are the enter handlers for those next
02:01page, previous, first, and last page links that you saw on the top of the
02:04document. We are essentially assigning click handlers to each one of those
02:09items and then functions to call, which are these guys right here. These
02:13functions just call into the pagedTable object.
02:17So let's take a look at the code before we go any further for the pagedTable.
02:22So if you recall from the earlier lesson back during the object-oriented part
02:27of the course, where I talked about creating your own objects, what I've done
02:31here is I've created an object called a pagedTable. A pagedTable is in part a
02:37wrapper object. It's going to wrap an HTML table. It's also partially just some
02:42custom properties and logic I have added to move through the individual pages.
02:48So over here in the HTML file let me call new PagedTable. We pass in the table,
02:56given an ID for which we want to have paged, and we pass in a number that
03:02indicates how large we want the page sizes to be; and that was passed in down
03:06here, the number 10. So we're defaulting to a page size of 10.
03:10So here in the object, we pass in the tableObj that we want to have paged, and
03:14this is the page size and we store those guys aside here in these member
03:19variables. We have a couple of internal things that we use to keep track of
03:23where we are in the current page and so on.
03:24So before we go any further, let's take a look down at the prototype objects.
03:28You can see that on my pagedTable on its prototype, I have defined some
03:31functions for last page and first page, next page and previous page. Basically,
03:36all these guys do is either increment or decrement or somehow operate on the
03:43CurPage index member, and then call a member function called goToPage. That's
03:49all the way down here.
03:51The goToPage function is what handles navigating to the particular page that
03:56the user wants to go to, whether it's first or next or last or previous or
04:00whatever, and we'll come back to this logic in a moment.
04:04In the meantime, let's go back up here and see how we start off. So when the
04:08object is created we store aside the rows in the table along with the page
04:14size. So we get the TBody and we store that aside because we're going to
04:17operate on it later, and we do that using the DOM function getElementsByTagName
04:20on the TBody. Again, there could be more of one these, so we just get the first one.
04:27Then we get the Rows and we're going to get all the table rows out of the
04:32TBody. We then make an Array, which is the size of the Rows array and we do a
04:37deep clone of all the Rows into that array. Now, this a very similar technique
04:42that I just showed in the previous example for sorting data, but that's not
04:46what we're going to be doing here, we're not going to be doing any sorting.
04:49This is only for keeping the rows in the manageable chunks.
04:53Then we have a variable here that tracks the size of the Array and the number
04:59of Rows. Then we have to figure out what the page size is going to be. So it
05:03turns out that if you pass in a page size of say 200 and there is only 100 rows
05:09in the table, then we reset the page size to be equal to the row count. That
05:13way we're not trying to display 200 rows when there is only 100, or 20 when
05:18there is only 10 or something like that.
05:20Then we have to calculate the number of page that there is going to be, and to
05:24do this we take the RowCount and we divide it by the PageSize. So if there is
05:2950 rows and the page size is 5, there should be 10 pages.
05:33Now, the math won't always work out perfectly so this is where we take
05:37advantage of a Math library function, this is built into JavaScript, called
05:42Math.ceil. Math.ceil stands for Math .ceiling. The Math.ceiling function
05:49essentially rounds up to the nearest larger integer in case the number that you
05:55give it is not an even integer number.
05:58So for example, suppose you had 20 rows and you asked for a page size of 7. So
06:0620 is not evenly divisible by 7. You would end up with two point some thing.
06:12This will round up to 3. So in that case you would have two full pages of 7
06:18rows each, and then on the third page we would have 6 rows. This is how we
06:22handle the situation where the number of rows is not evenly divisible by the
06:26page size the person wants.
06:28Once we've done that, we call the goToPage(0) function and that displays the
06:33first page of data in the table. So let's take a look at that. This function
06:38here is the goToPage function and it takes an argument, the page number that we
06:43want to go to, and all the other function for navigating the pages call this
06:47function in the end.
06:49So if for some reason the user or the programmer who is using this library
06:55passed in a PageNum less than 0, we just pin it to 0. Otherwise, if the PageNum
07:00is larger than the number of pages that we have, we pin that at the PageNum.
07:06So what we're going to do now is get the TBody from the table, and we're going
07:10to calculate which starting row the TBody should display the rows at. So we're
07:15going to multiply the PageNum times the PageSize. So if we're on page 0, we're
07:20going to start at row 0. If we're on page 1 and the PageSize is say 10, we're
07:25going to start at row 10. This is how we are going to calculate which rows to
07:30put in the TBody at any given time.
07:32Then we figure out what the endRow is going to be. The endRow is going to be
07:36the startRow plus whatever the PageSize is.
07:38Now, let's do some more math here, because recall in the earlier case if we had
07:4220 rows with a PageSize of 7, we're not going to have an even number of rows in
07:46the PageSize. So if the endRow turns out to be larger than the number of rows
07:52that we have, then the endRow is going to be the last row in the tables. So let
07:56me just pin that there.
07:58Then all we need to do is loop over each one of the rows, starting at the
08:03startRow and going through the endRow. In the NewTBody we just add the rows
08:09from the original TBody that we stored aside, into the NewTBody.
08:14Once we've done that we remove the existing TBody. We set the TBody for this
08:21object to be the new one we just created, and then we tell the table, hey,
08:25replace the old TBody that you had with the new one. That's pretty much all
08:30there is to it. So we've replaced all the rows in the TBody temporarily with
08:33the page that we're looking at.
08:36Let's go back here now. Just to make sure it works I'm going to view this in
08:41Firefox. You can see its working. I'm going to the last page. Here is an
08:46example by the way of a row count where the page size is not evenly divisible.
08:51You can see that we only have one row of data in the last page, but in the
08:56previous pages we've got 10 rows of data.
08:59I will go back to the first page, last page, previous, previous, so you can see
09:03it's working here. Let's make sure it also works in IE, and you can see that it does.
09:12So let's play around a little bit. Let's go back to the code and change the
09:17PageSize from 10 to 6, and now let's look at it in the browser again. You can
09:23see now that the page size is changed and now we have more pages.
09:27Now let's try making a page size of -- let's do 1,000 rows in the PageSize.
09:33You can see in this case the first page is the last page. So when I click on the
09:38controls here nothing will happen.
09:39Well, that concludes our last table example, so now you can see how to use an
09:46object to wrap a HTML construct in real world situations, and you can go ahead
09:53and use this code in your personal projects.
Collapse this transcript
Using in-place editing
00:00For this example, I'm going to show you how to edit the content of a page
00:05in-place using the DOM with JavaScript. We are also going to show you how to
00:11use the Modern Event Model to handle events that occur in the page. This is
00:15going to be a real world example of that.
00:18So here I have my page in the design surface and let's bring this up in the
00:22browser to show you what it does. So here we are in IE. I'm going to click this
00:30button here labeled Add New List Item. You can see that as I do this,
00:34I'm adding new items to my unordered list here in the browser page. I can also
00:39click on one these guys. When I do, you will see that it goes into editing
00:43mode. I can cancel and leave it the way it is or I can click on it and change
00:51the text. When I click Change, it takes place. I can also click on an item and
00:56delete it. Okay, so I think you get the idea.
00:59What I'm doing is I'm manipulating the page content and adding and changing and
01:03deleting items. So let's -- just to show you that it works cross browser,
01:08I'm going to do the same thing in Firefox. Okay, so here we are in the Firefox browser.
01:12I'll click Add New Item a few times, add few items, click. I can edit it,
01:18I can delete it, I can cancel and leave it the way it is. Okay, so you get
01:23the idea. Let's see how this works in the code.
01:27Here we are back in the editing tool that I'm using. This is Visual Web
01:31Developer, but you can use your own tool to do this. Okay, so switch over to
01:35the Source view. So a couple of things first. I have included my cross-browser
01:41event handling module and I have an external JavaScript file over here called
01:46ListEditing.js and I have got a style defined up here.
01:50So let's move over to the ListEditing code. That's this guy right here. So
01:56we'll roll down to the bottom. So down here at the bottom, I'm using my
02:00cross-browser event module to add a load event handler to the window object and
02:07the function that gets called is initListEditor. So let's scroll up to
02:12initListEditor and that's this guy up here.
02:15Pretty short function. Basically all it does is in a global variable we have
02:19called gTheList. It gets the element in the page that corresponds to the ID of
02:25the list. If you look back and mark up you will see that that is this guy right here.
02:31So we have this unordered list with a default item in it and it's got
02:35an idea of the list on it.
02:37So once we've done that, we add a click handler to handle the item clicks on
02:43list item tag. This is what enables us to edit the contents. But using the
02:47Modern Event Model we don't individually put event handlers on each individual
02:52list item, what we do is we add one click handler to the unordered list itself.
02:57That's the UL tag. In the event handler, we even figure out which list item got clicked on.
03:03So you can see here I'm using my event handler right here to add a click
03:07handler to the list itself. So I'm also assigning a click handler to that Add
03:13New List Item button that's above the list and that's also handling a click.
03:17Here is the function it's handling the Add New Item function.
03:22So a couple of things going on there. We attached an event handler to the list
03:27itself. The parent list tag and that's going to handle all the clicks on all
03:30the list items. So if we look at the code right here, you will see that the
03:34itemClick function is what gets called when a click event happens and that's
03:39this function right here. So this function will get called whenever the user
03:43clicked on something inside the unordered list. What we need to do now is
03:48figure out which list item tag was clicked on.
03:52So the way we do that, inside the itemClick function, I'm using my event
03:57handling module to get the event target given the event that was passed into
04:01this function. The target that comes back, it could be a couple of different
04:06things based upon what was clicked.
04:08So let's switch back over to the browser really quickly because I want to show
04:12you this. It's a little bit subtle. I'll go back to the source. Okay, so let me
04:18add a few list items. There's a couple of places I could click here. I could
04:21click on the text New Item itself or if I'm kind of subtle I can click right on
04:26that little bullet there. In both cases, the click is handled properly.
04:32The challenge however is that depending on where you click on the list,
04:35different elements are going to register the click. If I click directly on the
04:39text here, then the item receiving the click is actually not the list item tag;
04:44it's the text node that's inside the list item tag. Whereas if I click on this
04:49little bullet, it's the LI that's receiving the click event.
04:53So I have to handle both.
04:55Okay, so let's go back to the code and see how that happens. So we're back here
05:00in the code, let's go to the JavaScript. Once we've gotten the target that was
05:04clicked on, there's a couple of checks we have to do. First, we check to see if
05:10the targets node type. That's a standard DOM property is a TextNode and
05:15TextNode is a constant that I have defined up here. For TextNodes, the node
05:21type will be equal to the constant value 3. So if the TextNode is what got
05:26clicked on, then we have to get the parent list item of the TextNode.
05:32Now on the other hand, if user clicks directly on the list item itself, by
05:38clicking on that little bullet point there, then the target will actually be a
05:42list item tag. So let's take a quick look at this getParentByTagName function.
05:48You can see I'm passing in the string LI and the target, which is what was clicked on.
05:55So that's this function here. It's basically a little utility function. So this
05:59is the tag that I'm looking for and this is the starting point where I'm
06:02looking for it. So it's just a little loop.
06:05Basically I start off by getting the parent of the node that was passed in and
06:12as long as I have a parent, as long as its value is not null, then and look at
06:15the nodeName of the parent. Again that's a standard DOM property and I compare
06:19it to the tag that was passed in. If the two match, I know that I have arrived
06:23at the node I was looking for. Otherwise I get the parents of this node and I
06:28keep on going up the chain.
06:29So this will keep going up through all the parent tags until I reach the tag
06:33I'm looking for. If I reach the parent tag I'm looking for, I return it.
06:38Otherwise I'm not going to find it at all and I just return null. Okay, so when
06:44that function comes back I'll have the list item or I'll have nothing. In this
06:49case, I'll just have the list item tag itself.
06:52So a couple of things we have to keep track of here. First, we need to see if
06:55we're currently editing another list item because if we are, we have to remove
07:01those editing controls and move them to the item that we are about to edit. So
07:07we have a global variable we keep track of called curEditItem and if the
07:11curEditItem is not equal to null, then we figure which list item tag we're
07:16editing. And we're going to get the innerHTML. We're going to just resend it
07:20back to whatever its old content was because we're clicking away from it.
07:24We didn't click the change button.
07:27So we keep track of the old content that was being added and then we save aside
07:32the content that is being edited currently into the gOldContent global variable
07:39and then we call editListItem on the target that was clicked. So editListItem
07:44is the function that handles editing the content inside the LI tag.
07:49So let's scroll down.
07:52So this is the function where we create the editing controls, position them
07:56properly and so on. So what we do is when we come into this function we'll give
08:02in a list item that we're about to edit. So using the standard DOM property's
08:07firstChild and data, we get the content of the list item. So here is the list
08:13item. The firstChild means get me the first child inside the list item and for
08:18our purposes, it will be text data and the data property on text nodes is the
08:22actual text inside the node. So we save that aside in this variable here.
08:26Now we are going to create the controls that we're going to use to edit the
08:30list item. So here we create an input element and we create an id for it and we
08:35set its type to be text. Then we set the initial value of that editing field to
08:40be the TextContent that we just saved aside up here. So that gives the visual
08:44appearance of, when you click on the item, it looks like the edit control is
08:48being super imposed over the text that's already there.
08:51What we're going to do is we're going to replace the existing list item tag
08:58with the edit field that we just created. So here is the list item that we're
09:02editing, replacing the TextContent of the list item with the TextField we just
09:08created. That's what completes that effect. We get rid of the old TextContent
09:11and we put in the TextField that it looks like it's being super imposed over the text.
09:16Okay, now what we need to do is add the Change and Cancel and Delete buttons.
09:20So this is all just very straightforward. We use the DOM to create the various
09:23input elements for the buttons for OK, Cancel and Delete. Then we assign the
09:27event handlers that will be called when each one is clicked. So in the case of
09:32the Change, we have commitEdit, for Cancel we have cancelEdit and for Delete we
09:36have the deletItem functions.
09:40So once we've created them, we append them to the list item so that that way
09:45they appear in place. Okay, so let's go back and take a look at this in action
09:49so we can see what's going on.
09:51So remember when I click here what's going to happen is the edit field is going
09:55to be created along with those three buttons and the edit field is going to
09:59replace this list item you see right here. So now that edit field gets placed
10:03in there and then these three buttons just get added alongside this TextField
10:07right here. So now let's go back and finish the code.
10:13Now in the case the each of the event handlers, we are going to take different
10:16actions based upon which button was clicked. So in the case of the Change
10:20button, we're going to call the commitEdit function. That's going to take an
10:24event argument.
10:26So the TextField, we're going to get that by its element id, which is itemText,
10:30and we set that when we created the button. So we're going to get the value out
10:33of the TextField and store that aside in a TextContent variable. Then we're
10:38going to tell the TextField to get the parent node, which is the list item and
10:43set its innerHTML to the TextContent.
10:46Now this will automatically destroy the TextField and the three buttons. So it
10:52has the added benefit of getting rid of the controls once we are done editing.
10:56We don't have to explicitly do that because we're changing the entire innerHTML
11:00from the TextField and those buttons to just the text that we were editing.
11:05That was pretty clever I think.
11:07In the case of deleting an item, that's pretty easy too. So once again we get
11:11the TextField and we get it by its id. Now return the list to just remove the
11:18child that we added. We are going to remove the entire list item, which is the
11:24parent of the TextField that we put into it. So remember the list item now
11:28contains this TextField and we are just going to tell its parent node, Hey!
11:31You'll get rid of the list item that is the parent of this TextField.
11:36Finally, in the case where we cancel the edit, all we need to do is set the
11:40innerHTML of the list item, which is the parent of the TextField that we put
11:44into it, back to whatever its old content was. Okay, so one more time let's
11:49take a look at it in action.
11:54So this is adding a new item, which is creating new list item tags on the fly.
11:57That should be straightforward. When we click, we create these controls and
12:02replace the content of the current list item with them and we set the TextField
12:07value to be the string that was in the list item and we can go ahead and change it.
12:11Now remember when we click the Change button, we're going to replace the
12:16TextField and these three buttons with this TextContent right here. That has
12:21the added benefit of getting rid of all the control as well. And then we click
12:25Delete. We just get rid of list item itself.
12:28So that's pretty handy. We've seen how to use the Modern Event Model, to handle
12:32events that occur inside of an item, regardless of where it was clicked, we can
12:35figure it out later. We have also seen how to dynamically change and edit page
12:39content using the DOM.
Collapse this transcript
Setting up an adaptive layout
00:00For our last example, I'm going to show you an example of what's called
00:03adaptive layout. This is a layout that changes along with the window's size. So
00:13I'll show you what I mean because it's easier to show it to you than to
00:15describe it to you. I'm going to bring this document up in the browser.
00:19A couple of things I want to point out. First, you can see that this is a
00:23pretty traditional three-column layout. There is a masthead here and I have got
00:28three columns of content. There is a nav bar over here and I have got a footer
00:32down here that's at the bottom of the page with a border around it. So watch
00:36what happens when I start to resize the page.
00:38It starts out; the content is nice and big, easy to read. So I'm going to grab
00:42the little resize down here and I'm going to resize the window. Do you notice
00:45how as the window gets smaller, the text size has changed to reflect the fact
00:51that I have less space to display the information in? So the text actually got
00:55smaller, so I can fit more stuff on the page. Okay, so far so good.
00:59Let's go ahead and keep on making it smaller and smaller. Things are getting
01:03kind of tight now. Oh! Look at that. So now the layout changed pretty
01:09dramatically. The link list over here goes horizontal, the right column
01:16disappears entirely and the middle column content header gets smaller. You can
01:22see that the footer got smaller as well and the masthead text got smaller.
01:26So this is an example of taking advantage of the screen real estate to display
01:31more information as you have it. As things get smaller, maybe changing the
01:36layout around, so that you can display more information. So let's take a look
01:42at the code to see how this works.
01:46Here I'm in the design surface. Let me switch over to the code, so you can see
01:50what's going on. A couple of things I want to point out. First, here is my
01:54cross-browser event handling module and I have got an external JavaScript file
01:59here that's handling the layout sizing.
02:01So the content of this document is essentially just your regular HTML.
02:06It's a whole bunch of divs. You can see each of the divs is taking up different space
02:11in the document. Other than that, it's just pretty straightforward. There is no
02:15style information in here or anywhere. So let's take a look at the CSS style
02:19sheet that goes along with this document.
02:21So you can see I have defined several different style sheets. There is
02:24bodyNormal and bodyNormal has a whole bunch of styles for the items in the
02:29page. Then we have bodyLarge, again, with the same items in the page. Then we
02:35have bodyMedium and we have bodySmall. So we have a whole series of different
02:41style sheets defined based upon what size the window is. So let's take a look
02:48at the script code that controls how the styles are going to apply.
02:52A couple of things I want to point out. Right here, I'm defining a new module
02:59for this code that's going to add onto the cross-browser module I have defined
03:06for my event handling. So you can see I'm defining a new sub-module on top of
03:11the com_joemarini object. The other one is events. This one is ADAPTIVE_LAYOUT.
03:16Here inside the ADAPTIVE_LAYOUT, I have got some properties. I have got some
03:20functions. You can see this is actually a very small file. I mean all of this
03:24ADAPTIVE_LAYOUT is being handled by some pretty small code. So let's take a
03:29look and see how it works.
03:31Well, down here you can see that I have got my cross-browser event module,
03:37which is adding an event handler for the window load and the window resize
03:41events. So for the load event, we are calling the initSizes() and
03:46setStyleForSize() functions. We'll get to that in a second. Then we are also
03:50adding an event handler for the resize event on the window and that's also
03:54calling the setStyleForSize() function.
03:57So the initSizes() function right here, what it's basically doing is I have an
04:02array called ScrnSizes. ScrnSizes is going to be holding a series of objects
04:09that define screen dimensions along with the class of style sheet that should
04:14be applied for that width of the window. So you can see here I have got a width
04:21defined of 800 and -1. So for minimum width is 800, maximum width is -1.
04:28That's a special flag we'll look at in a moment. That's going to be corresponding to
04:33the bodyLarge class.
04:35The next one down, the minimum width is 400, the maximum width is 800 and
04:39that's Medium. Then we have got -1 and 400 for Small. So that's how we
04:44initialize the sizes. Now let's see what setStyleForSize() does.
04:49That's this function here.
04:51setStyleForSize() essentially starts off by getting the client width of the
04:56window. So we use the clientWidth property on the documentElement. Then it's
05:00just a simple matter of looping through all the screen sizes to see which one matches.
05:05Now we use the -1 flag as sort of an open-ended indicator. So if we look back
05:10up in the screen sizes here, this means minimum width is 800 and maximum width
05:15is unbounded, it can be 2000. Similarly down here, it means no minimum width up
05:21to 400. So in effect, it basically means a width anything less than 400. This
05:28one means in effect with anything greater than 800, whereas this one means
05:33between 400 and 800. Okay, so let's scroll down to the setStyleForSize() function again.
05:39What we are doing here is we are looping through all of the screen size
05:43elements in the array to see which one matches. So in the case of minimum width
05:49being -1, we then check to see if the clientW is less than the maximal
05:55specified. In that case, we set the document.body.className to be the style
06:01sheet class that corresponds with this object.
06:04Now on the other hand, if the maximum width is -1, we then check to see if the
06:08clientW is greater than whatever the minimum width specified was. Again if it
06:13matches, we just set the class of the body to the class that goes along with
06:18this screen size object.
06:20Then finally, we check the conditions to see if the clientW is between any of
06:26the two sizes specified in the array. Once again, if we have a match, we just
06:31simply set the body's style sheet to be the class that corresponds with that object.
06:36That's pretty much it. It's pretty straightforward. So let's go back to the
06:42content here. Once again, I'm going to bring up the browser. You can see that
06:47what's happening is as the window is being resized. That resize event is being
06:50fired off. You can see that once we fall into one of the ranges specified by
06:56those properties on the array object that we have specified, we are just simply
07:00changing the body style sheet to match whichever style sheet went along with
07:04that particular screen size object. Just to prove to you that this also works in Firefox.
07:09Now Firefox is a little bit different and the reason is because Firefox has a
07:12bug in it. Firefox doesn't fire the resize event on the fly, it waits until you
07:18have finished resizing the window. So you won't see it on the fly here.
07:21I actually have to pause for a second and you can see it took effect.
07:25So I'll resize back out. You can see after I pause, there it takes effect. So I'm going
07:30to resize all the way down. You can see that when I pause, that's when it takes effect.
07:35Now you have seen how to adapt layout to changes in the window size on the fly
07:39using JavaScript events and some CSS.
Collapse this transcript
8. Tools and Tips for Developing and Debugging
Discovering tools for debugging and developing
00:00Just until recently, I would say within the last couple of years or so, getting
00:03good tools for debugging and developing websites was dicey. The tools were not
00:12usually of very high quality or they weren't very good or very feature
00:15complete. That thankfully has changed dramatically over the last few years.
00:20People who are developing websites now have access to some really great tools
00:24that can help them debug their pages and help them design their code a lot more
00:29efficiently than ever before.
00:31In this section, I'm going to talk about some of these tools. I'll show you
00:34three plug-ins that are available for Firefox and a couple that are available
00:39for Internet Explorer that you can use in your web development to improve your
00:44processes and debug your pages and just really be a lot more efficient.
00:49So for Firefox you have a few available. You have got YSlow for Firebug. YSlow
00:55is an extension for Firefox from Yahoo. It helps you to maximize the
01:00performance of your web pages according to Yahoo's rules for high performance
01:05websites. If you have never seen this website before, Yahoo basically came out
01:10with a set of rules a little while back that describes how to get the most
01:15performance out of your web pages.
01:16The YSlow plug-in for Firebug quantifies these rules and automatically runs
01:22them against a web page in the Firefox browser. Then provides you with a
01:27report, so you can see where your pages are slowing down and why.
01:32The Dev Bar for Firefox extension is another extension for Firefox that
01:36provides a lot of very useful utilities for building web pages. It's available
01:41for free and I have provided the URLs for all these tools here.
01:45Then finally, Firebug is an extension for Firefox that provides debugging and
01:50monitoring and a whole bunch of other useful development tools. If you are
01:53doing any kind of web development and you are using Firefox, you should really
01:57get these extensions and install them. They are all free and I have provided
02:00the URLs for all of them. So download them and start using them. I'll take a
02:04little tour of these features in a few moments.
02:08There is also some really great tools available for Internet Explorer.
02:11The first is Developer Bar for IE. This is a free extension from Microsoft for
02:16Internet Explorer. It provides a set of utilities, like inspecting the DOM and
02:22viewing CSS and HTML code. You can use it to turn off browser features to see
02:27how your site behaves. It's kind of really great feature set and it's available
02:31for free. So you can download it directly from Microsoft's site.
02:34Also, there is Visual Web Developer Express. This is the tool that I have been
02:37using throughout this title to develop my code and do debugging. It's also free
02:42and it's available from Microsoft as well. It provides a really great editing
02:46environment and a debugging engine. You can download it at the URL that I have
02:51got listed there.
02:52Okay, well let's just dive right in and start taking a look at some of these
02:56tools. I'm going to start off with the Firefox ones and then move onto
03:00the Internet Explorer ones.
Collapse this transcript
Using the YSlow plug-in to analyze performance
00:00Okay, so here I'm in my browser. The first tool that I'm going to talk about is
00:03the YSlow plug-in for Firefox.
00:06The YSlow plug-in is a free extension. It's available from Yahoo. Actually,
00:11why don't I go up and take a look at the tools that are installed? I'm going to go
00:14to the Firefox Tools menu and look at the Add-ons. These are the Add-ons that
00:18I have currently installed in my version of Firefox. I have got Firebug.
00:22I have got the Microsoft .Net Framework Assistant, Web Developer and YSlow.
00:26I was able to find these plug-ins pretty easily. If you just go to the Firefox
00:31website and do a search on developer or something like that, you will get a
00:35range of pretty good hits for developer related technologies that you can
00:39plug-in to your browser.
00:41So let's begin by looking at the YSlow plug-in. So YSlow, when you install it,
00:48it adds a little icon down here in the Status bar. You see YSlow with a little
00:52tachometer down there. YSlow is a plug- in that helps you analyze why pages run
00:57slowly or load slowly. That's why it's called YSlow.
01:01The YSlow plug-in was developed by Yahoo according to their rules for high
01:05performance websites. So I should be specific here. YSlow is actually a plug-in
01:10for Firebug, not Firefox proper. So in order to use it, you have to install
01:16Firebug first.
01:18So what I'm going to do is click on the YSlow plug-in. You can see that it
01:21brought up the YSlow window down here. I'm going to refresh the page. Then I'm
01:28going to click on the YSlow plug-in. You see that there it is loading the page.
01:34What's happening is YSlow is running this page against a series of rules that
01:38Yahoo has developed. You can see here that the page came back with a
01:42Performance Grade of A (96) point. So it's doing pretty well, but it looks that
01:46there are a couple of places where we can make some improvements.
01:49So let's take a look at some of these rules and see what's going on. So you can
01:53see here that Yahoo has defined a rule called Make fewer HTTP requests. So
01:58let's click the little expander icon and see what's going on. So you can see
02:01here that this page has four external JavaScript files and it has 11 CSS
02:06background images.
02:08So it seems like if I want to speed- up performance in this area, I can
02:11consolidate some of these JavaScript files down and maybe find a way to
02:14eliminate some of these background images and the page will load even faster.
02:18So now when you click on one of these rules, you are taken right to the Yahoo
02:23website. In fact, you are taken right to the exact rule that explains why
02:28following it will result in faster performance for your web pages. So in this
02:32one, you can see Minimize HTTP Requests. Right upfront, it says 80% of the
02:37end-user response time is spent on the front-end. So anything that you can do
02:41to minimize the number of requests that your page makes back to the server,
02:45obviously that's going to speed things up.
02:48Let's close that down. You can look at some of these other rules. For example,
02:52here's a rule Put CSS at the top and I have got a B on that one. So you can
02:56find out why. It says 1 external style sheet was found outside the document
03:00HEAD. It seems I need to fix that. So again, I'm going to click on the rule.
03:06It turns out that putting style sheets into the document head makes pages appear a
03:11little faster.
03:11So again, this is a great section of rules. You should take a look at these,
03:15read them, understand them. These will help you build faster web pages.
03:21That's the YSlow plug-in, let's go ahead and move on to our next tool.
Collapse this transcript
Using the Firefox Developer Bar
00:00Another really great tool that I would like to use in my web development, and
00:04you have probably been noticing it as I bring up Firefox each time, is the
00:08Developer Bar extension for Firefox. That's this guy right here.
00:13I found this by going to the Firefox Add-ons. Just go up here, go to Add-ons.
00:20If you want to get Add-ons, you can go ahead and just click the Get Add-ons.
00:24I just type in developer. You can see there is a whole bunch of developer related
00:28extensions available that you can install right from here and that's how I found it.
00:33You can also, however, just go straight to the website of the person who
00:36created it. That's this guy right here, Chris Pederick. It's a really great
00:40extension. I highly recommend you download it and use it because it's got some
00:44really great useful utilities to help you in your page and scripting
00:49developments. So let's take a look at some of those features.
00:52First, you can test how your page responds when JavaScript is turned off by
00:56going under the Disable menu. There is a whole bunch of things you can disable,
00:59but I'm just going to highlight a few of these. You can disable All JavaScript
01:02in the page. Now I'm looking here at the Firefox homepage and it doesn't use a
01:07whole lot of JavaScript, but you can see the behavior changed a little bit.
01:10The idea here though is that if you disable JavaScript, you can test how your
01:14page responds when your script isn't available. You can also disable things
01:19like CSS. So what I'm going to do is go to CSS menu and choose Disable Styles.
01:24I'm going to say disable All Styles.
01:26Here you can see how your page looks like when styles have all been turned off.
01:30You can see that the Google page here, which is pointed to turn to Firefox homepage,
01:34it's still pretty usable when CSS is turned off. So I'm going to turn that back on.
01:40In addition to being able to disable and enable features, the Developer Bar
01:45provides all kinds of information about content in the page. So for example, if
01:51you look under the Images menu, there is all kinds of information you can get about images.
01:56First of all, you can turn images off to see how the site looks when images are
01:59turned off. I'm going to turn them back on. But you can do things like, for
02:02example, display what the image attributes are? So here you can see that each
02:07one of the images, they now have a little overlay on it that says what it's
02:10size is. You can also do things like, display what the image paths are and roll
02:17over that, it's going to show me a little pop-up of my image information.
02:21So some really good features for working with images and page content. If you
02:25go to the Outline menu, you will see that there is some features in here as
02:29well. You can outline things in the pages. So for example, you can outline
02:33tables. You can see that this site here has a table in it that's being used to
02:38layout the information.
02:39When I choose Outline Tables, it puts outlines around the table itself as well
02:44as the cells that are in the table. So I can very quickly find where in my page
02:49the tables are. So I'm going to turn that off really quick. There is a whole
02:52bunch of outlining you can do. You can Outline Headings or Frames. You can
02:56outline block level elements like divs. Just get a quick idea of how the page
03:00is carved up.
03:02Under the Information menu, there is a whole bunch of really useful stuff.
03:05You can display all kinds of information about the document and the content.
03:10There is a lot to go through, so I'm not going to go through all of it, but the idea
03:13is like, so for example, displaying Element Information. You can go ahead and
03:16roll over something. When you click on it, in this case I have clicked on a div
03:20and it's showing me all the attributes, the positioning information, all that stuff.
03:23You can just keep on doing this for all the stuff in the page. This is a really
03:27useful way to get a quick overview for the information that's in your page. So
03:32if you are writing scripts, for example, that depends on positioning or ids or
03:36whatever, you can see really quickly what your page is composed of and how it's composed.
03:41It gets better though. One of the things I want to show you quickly is really
03:45great. There is a way to not just view CSS information; you can actually edit
03:50the CSS live in the page. So let's look at both of those.
03:53I can view the CSS data. You can see here I have clicked the View CSS option
03:58and a new tab popped-up showing me all the CSS information for this particular
04:02page. Now it's all being compressed down into one big long line, but it's
04:07useful to see what style information is on the page. But I can actually also
04:12edit it in real time.
04:14So I'm going to say here Edit CSS. I'm going to look down in here really
04:18quickly. Now take a look here, here's the style sheet that defines the
04:22font-family for the page content and the body, for example. Right now, it's
04:27Arial. I'm going to in real time just change that to Verdana. You can see that
04:32it updated the page with the new CSS. I want to change the body color to just
04:38fully red. You can see that the text in the page has changed.
04:42So this is a really great way to test out new CSS code while the page is live
04:47in the browser and see what the results are going to be. So again a really
04:52useful extension. I highly recommend that you download this and use this.
04:55It will be an indispensable tool in your toolbox pretty quickly.
Collapse this transcript
Debugging with Firebug
00:00One tool that no JavaScript developer should be without is Firebug. That's what
00:06I'm going to show in this particular section.
00:09Firebug is an extension to Firefox. It's a free extension. You can go get it in
00:13a number of places. You can get it at getfirebug.com. So you can download it
00:20from here. You can also go into Firefox's Add-ons Manager and do a search on
00:26Firebug and download it from there as well, but you can also just go to
00:29getfirebug, click the Install Firebug button and you are off and running.
00:35So let's take a look at the Firebug extension because it provides a lot of
00:39really useful utilities and features for debugging and developing your
00:45JavaScript and your pages. So when you install it, it appears under the Tools
00:50menu. There is a Firebug menu right here.
00:52There are a couple of different ways you ca use it. One way to use it is Open
00:56Firebug in a New Window. That opens the Firebug extension up in a window of
01:00it's own which may or may not be useful depending on how many monitors you have
01:05or personal preference. You can also open it up as a sub-window, it's own pane
01:12down here. I would like to do it this way.
01:14So let's take a look at some of Firebug's features, they are really pretty
01:17useful. The first feature I want to show you is the HTML tab which I have
01:21selected right here. The HTML tab allows you to explore the content of the
01:27document in a tree form. You can see as I'm mousing over stuff, as I mouse over
01:33this div, for example, that div at the top of the page is highlighted.
01:36So I'm very quickly getting a feel for what the content of my page looks like,
01:40just by mousing around. And if I open up the center here, there is a form.
01:44You can see that as I'm mousing around the table, there is all kinds of stuff in
01:49here. I'm mousing over each table row and so on.
01:53So anyway, the HTML tab shows you the contents of the file. So I can select an
01:58element, the table. When I select it, over here on the right hand side I get a
02:03whole bunch of information about what is selected in the document. So in this
02:07case, I'm looking at the Style tab.
02:09This Style is showing me what styles are applied to the element I have
02:14selected. These styles right here are directly applied. Then down here you can
02:19see, it says Inherited from the body, these are the properties that are being
02:22inherited from the body tag.
02:23I switch over to Layout. The Layout tab shows me what the dimensions are for
02:29the selected element and it's using the box model here. So you can see here is
02:33the border, the padding, the margin, the offset and so on. If I click the DOM
02:37tab, it shows me all of the DOM properties for the selected element.
02:43What's also really useful is if I want to get information about a specific
02:47element in the page, I can just simply click the Inspect button and then
02:51Firebug goes into what's called Inspect mode. Now I can mouse around inside the page.
02:57You can see as I'm moving the mouse around, I'm able to select different
03:02elements and get information about them. As I'm moving the mouse around,
03:06you can see that the HTML and Style panes are keeping up with the selection to show
03:13me what's selected.
03:14So I can go ahead and select this image right here and when I click on it,
03:17we go out of Inspect mode. Now the item I clicked on is highlighted right here in
03:23the HTML tab. I can just inspect it and get it's properties and so on,
03:28it's really useful.
03:30Let's switch over to the DOM tab. The DOM tab shows me the DOM for the current
03:35page. We are looking here at the Firefox Start page on Google. So I'm looking
03:41at the DOM content and you can see that it's pretty straightforward. Here is
03:46the document root element. You are probably familiar with that, if you are
03:49familiar with the DOM at all.
03:50So I can just start drilling into the objects inside the DOM pane here.
03:54Let's scroll down to the childNodes. You can see that the first child of the document
03:58is html. I just keep drilling in. Here is the html tag. You can see as I scroll
04:05down, there is firstChild and that's html tag. If you scroll down a bit more,
04:10there is the childNodes. There is the head and the body.
04:12So I just go ahead and keep on drilling in here and learn about all different
04:15kinds of information in my document. So that's pretty useful. Again, as I'm
04:20scrolling around over stuff, let's go a little bit deeper. Here is the body and
04:26firstChild is the div. You can see that I'm getting the same kind of
04:29highlighting as I mouse around in my DOM tab, as I was in the HTML tab. You see
04:34as I'm mousing over this div, up here this little guy is highlighting right
04:37here, also very useful.
04:39I can also edit properties in this frame in real time. Now I would have to find
04:44one that's useful to edit. So let's see if I were to say edit, let's try this
04:51one for link colors. So instead of having "#0000ee" for link colors, let's
04:56change that to "#FF0000". You can see, let's go back in. No, it doesn't seem to
05:02have any effects but you can edit properties directly in this panel.
05:06So for example, if I wanted to edit the innerHTML right here, I could.
05:09It's probably pretty dangerous, so I won't do it. Anyway, it gives you full access
05:13to the page though. Now let's move on and look at the CSS tab. So using the CSS
05:18tab I can do some pretty interesting stuff. So not only can I inspect the CSS
05:22code, but I can also edit it in real time. A reason I might want to do that is
05:27because I might be looking at my page in the browser and I want to see how
05:31small changes to my CSS might affect the page.
05:34So here we have a style sheet that assigns the Arial font-family to the body.
05:40I'm just going to go ahead and change that to Verdana and see what happens.
05:43You can see the page is updating in real time as I'm doing this. So you know that's
05:47just cool, we'll make that Courier. Now you can see that the fonts are changing.
05:52So we'll go back and change it to what it was. You can also see that I can add
05:56style sheet selectors on the fly, if I want to, as well. So if I wanted to say
06:00the background-color: red; you can see that I can get really dangerous really
06:07quickly. I'm just going to click on the delete for that guy.
06:11So that's the CSS tab. Let's look ahead at some other features. I'm going to go
06:16back to the HTML tab to demonstrate a really cool feature of Firebug. I have a
06:22little search box up here and I can start searching on anything in any of the panels.
06:27So, if I started typing say body, for example, you can see that the body tag is
06:32being highlighted as I'm doing that. Or if I was looking for something say gbh,
06:38I'm searching for a thing that I have class of gbh on them. That's also a
06:42really great feature. If you have long documents and you know that there is
06:45something in there with an id or whatever, you can just start typing in this
06:49little search box right here and it will pop right before.
06:52But the real power of Firebug comes when you want to debug your scripts.
06:58Firebug provides a really powerful debugging mechanism. So let's take a look at
07:03how that works. I'm going to go with the Script tab here and I'm going to
07:06enable the Script tab. The reason to enable it is because if you leave it
07:10enabled all the time, it will degrade the performance.
07:13So what I'm going to do is debug one of our previous examples using the Firebug
07:20scripts debugger. I'm going to switch over to the code now. This is the code
07:24for the table sorting example that we did in a previous section. This was the
07:31progressive enhancement example.
07:32So I'm going to go on to the TableSorting JavaScript code. Now, I can set what
07:37are called break points in my code. Break points help me freeze the execution
07:42of the script at a certain point. So I can see what's going on and expect some
07:46of these variables and objects. insertSortControls is one the first thing
07:50that's called. You can see that when the window loads, insetSortControls gets
07:56called right away.
07:57What I want to do is go up to the insertSortControls function and right at the
08:00top, I'm just going to type in the word debugger. Now I'm going to save it. So
08:05this is a command that says, "Hey debugger! When you come across this statement
08:09freeze execution on this line." Okay, so I'm going to save that.
08:13Now I'm going to switch back over to Firefox and we are going to see what
08:16happens. I'm going to go load that local file. So I'm going to say Open File
08:22and we are going to go to the exercise_ files. I'm going to go to TableSorting,
08:28okay. You can see that as I loaded the page into the browser what happened was
08:33Firebug came across this debugger statement and froze execution right there.
08:38That little yellow triangle shows me the current line that Firebug is about to
08:43execute. So we are just sitting there waiting, right now nothing is happening.
08:47You can see that as I'm moving the mouse around, I'm getting some pop-up
08:50information about elements in the page. Now it's undefined because we haven't
08:53executed the code yet. So what I want to be able to do is step over individual
08:59statements and see what effects they have.
09:01So you can imagine if I had a problem in the script somewhere, I would want to
09:05be able to stop execution and examine my variables and all that good stuff.
09:10I'm going to go up here into this Firebug bar right here and there are a couple of icons.
09:14This icon right here is Continue. If I press Continue, then the script will
09:18just keep on executing normally. It will just go off at this break point right
09:22here and probably either never come back or if this code gets executed again,
09:26then it will stop here again.
09:27I can also step into a function or I can step over a function or I can step out
09:33of a function. What I'm going to do is I'm going to use the step over to step
09:37over each individual statement. So I'm going to step over debugger. You can see
09:41that when I stepped over the debugger, now I'm into the function and I have got
09:44my variable right here. I'm going to step over that statement again. You see
09:48that oLink is now undefined.
09:50So now we are going to execute the statement right here,
09:51Document.getElementById("ItemDescend "); So when I step over that statement --
09:56okay now look at the pane over here on the right hand side. This is the watch
10:00window. The watch window shows me the values of certain variables and objects
10:07that are in scope over here, in this particular function or within the scope
10:12chain, functions that have called this function.
10:14So you can see that oLink has now been set to this link tag with an id of
10:20ItemDescend and it's also showing me the contents of the href. I can expand
10:25this and since it's a DOM element, I get access to all the DOM properties in here.
10:31So this is pretty interesting. What I can do however is if I want to like step
10:36over each individual statement one at a time, I can set what's called a break
10:40point. So I'm going to go ahead and set a break point down here on
10:45addEventHandler. I did that by clicking in the tab next to the line number.
10:50The green line number means that a break point can be set there. A gray number
10:55means we can't set a break point there.
10:56So I set a break point on this addEventHandler call and I'm going to click
11:00Continue. So execution is going to continue until it gets to that break point.
11:05So now that I have got to my break point, I can do some more interesting
11:09things. I can step into this function. So when you are on a break point and
11:14there is a function here, I can click the Step Into icon right here. Now we are
11:18going to step inside addEventHandler to see how it works.
11:20So we stepped inside addEventHandler and now we are inside this function. If we
11:25look at the stack window, we can see what's going on here. This is the top of
11:31the function called stack. This was the window onload being called from an
11:34anonymous function. This is my insertSortControls function right here and if we
11:38click on it, you can see where we are going to step back out too. This is where
11:40we got called in. And if we click on addEventHandler, you can see that this is
11:44where the current execution is.
11:46So the top function here is where the current line of execution is. So now we
11:50can step. Since we know how this is going to work, I'm just going to go ahead
11:53and step out. Now we have returned back outside the addEventHandler function.
11:59So this is really great. I can inspect variables. I can see what the values of
12:02certain things are. If something was wrong, I would be able to trace through
12:06the code and see what's going on. So let's go ahead and set a different kind of break point.
12:10So remember that this code sorts the content of the table by using the sorting
12:15callback. So what we are going to do is up in the code that sorts the table,
12:19this is the sortCallBack right here. I'm going to set a break point on this
12:25line right here. So this line comes after the lines of code that extract the
12:31data that's being sorted on from the table.
12:34I am going to do something special with this break point. I'm going to make it
12:37conditional. I'm going to only break on this break point when the value of
12:42text1 is equal to say the word Honey. So I'm going to right-click. You can see
12:50that Firebug is saying, "This break point will stop only if this expression is
12:53true." I'm going to type in text1 == " Honey". I hit Return and now you can see
13:03that the break point has a little question mark on top of it. That's called the
13:06conditional break point. It breaks only if a certain condition is met.
13:10So now I'm going to hit Continue. So now the page has loaded and everything is
13:14working normally. You can see I'm going to sort the table. So I want to click
13:19on ascending sort arrow. Look our break point got hit. The reason our break
13:24point got hit, if we go back to the watch window, is because -- now look at
13:29that, text1 is now equal to Honey. So we were able to set a break point on a
13:35line of code and attach a condition to it.
13:37This is a really-really powerful feature. Debugging JavaScript is so much easy
13:42when you have a tool like Firebug to use. There is also some great
13:45documentation online. If you go to the getfirebug site, they have a much more
13:50in-depth tutorial on how to use it but this is a tool you should not be without
13:53if you are developing JavaScript in a practical and effective way.
Collapse this transcript
Using the Developer Bar in Internet Explorer
00:00So I'm going to switch gears for a minute now, and talk a little bit about the
00:04utilities and tools available for Internet Explorer. Let's start off by looking
00:09at the Developer bar. There is a Developer bar that's available for IE, just
00:14the same way that there is one available for Firefox. Now, it's this little guy
00:17down here. I'm going to just grab this and expand it out.
00:22The Developer bar provides a lot of the same kind of features that we saw in
00:28the one that's available for Firefox, and again this is available for free.
00:33I provide the URL for this in the slide that proceeds this section right here.
00:38You can also just do a search on Developer bar IE, and it will come up for you.
00:42Let's take a look at some of these features.
00:44But first, what I want to show you is that this Developer bar has a DOM
00:48Explorer and HTML Explorer in the same way that the other one for Firefox does.
00:53You can see that, as I'm clicking the content in the Explorer here, you can
00:59probably just make out that the outlines are blinking here in the document as I
01:04select different things. So if I select the head, this guy blinks, select the page,
01:07this guy blinks, and if I go into the Head div, if I select this one,
01:12maybe it's blinking.
01:13So this is a way for me to search around in the document and see visually the
01:18corresponding element that I'm clicking on here in the Explorer. Another great
01:23thing about the HTML DOM Explorer over here is that as I change the selection,
01:28there is a couple of panes over here that show me not only the attributes that
01:32are available on the selected element, but also the style.
01:36So this shows me all the style information that is applied and it's only
01:41showing me the ones that currently have a value. I can also show the default
01:44style values, these are the ones that are added by the user style sheet that
01:48comes default with IE.
01:51I can click that off and now it's just showing me the applied styles again.
01:55Just like elsewhere, I can double-click and change these values. I'm not going
01:59to do it, because it will probably screw up the page, but if I'm testing and
02:02building a page, I can change these values and see what the effects are on my page.
02:07Another really great feature of the Explorer is I can do things like
02:11right-click on an element in the page, and then choose Element Source or
02:17Element Source with Style. If I choose Element Source, I get a window that pops
02:21up that shows me the source code just for that element. You can see here that I
02:25selected this Div right here, and it's showing me all of the source code that's
02:31available, not just for that particular element, but all the child elements
02:34inside of it.
02:35Alternatively, I can say Element Source with Style, and that will show me not
02:40only the element itself, it will show me the CSS code that goes with it as
02:44well. So you can see here these are all the CSS rules that are being applied to
02:47it, and let me scroll down and there is the source code for the elements.
02:53There is also a way for me to search in the page for a particular element.
02:59That's this button right here. This is the Select Element by Click button. So
03:03I'm going to click this guy and then, as I mouse around in the page, you can
03:07see that individual items are being highlighted as I mouse around.
03:11So I can go ahead and stop and click on any one of these guys. When I click on
03:15it, the HTML Explorer will zoom right to the element that I chose. So in the
03:20case of this Hotmail item right here, you can see that it's zoomed right to
03:23this anchor tag which is inside of an H2. So you can see that I'm inspecting
03:27the content of this element right here, and again, here is all the styles that
03:32are applied to it. I can also find individual elements.
03:35So for example, if I wanted to find an element now, Select Element by Click is
03:40currently active, I'll deactivate that and say Find Element. I can find an
03:44element using one of a variety of methods. I can search for an element with a
03:50certain name. So if I search for Body, you can see that the BODY tag would come up.
03:55However, if I said Find Element with, say, a Class and I put parent on it,
04:03you can see it's going to find the nearest element for parent. I can scope the
04:06search by going way back up to the top here, selecting HTML and say Find
04:11Element and Class with parent. Then I can just go ahead and keep doing Find
04:15Next, and then Find Next in the case of more than one element.
04:20So that's really pretty powerful. I can also disable certain browser features,
04:24so I can see what my page will look like when certain features aren't
04:27available. So by clicking the Disable menu, I can disable all the CSS and take
04:32a look at how my page looks. You can see that all the content is still
04:35available even I've disabled the CSS styles. I can go ahead and re-enable that.
04:41I can also disable JavaScript.
04:43So if I disable the JavaScript, then I can test my page to see how things
04:48behave when script is not enabled. I'll go ahead and re-enable that. Under the
04:54View menu, there are some really great features in here. I can do things like
04:59view Class and ID Information.
05:00So if I choose this, you'll see that the elements of the page get overlaid with
05:05information about their classes and their ID attributes. Turn that off. I can
05:10view a Link Report. This shows me information about all the links that are in the page.
05:15So if I wanted to run a report and do a search on what links are being hitting
05:19to page and where, I can do that. I'll close this tab. There is all kinds of
05:26interesting information that you can view here under the View menu. You can
05:30also view the Selector Matches.
05:32Viewing the Selector Matches will actually go through and generate a report for
05:35all of the CSS selectors that generate matches for items in the current page.
05:41Now, that can take a while so I'm not going to do it right now, but choosing
05:44this option generates a report that shows you all the different CSS rules that
05:49generated matches from your style sheets.
05:51Under the Outline menu, this helps me find items in the pages like tables and
05:57divs and anything else that I want to outline. Now, I can outline any element,
06:00but there are some presets for me that I can use. So for example if I wanted to
06:03outline all the tables, I can say Outline Tables. Now, it turns out this page
06:07doesn't use any.
06:07So if I said Outline Div Elements you can see that what's happened here is all
06:12of the elements in the page that are div tags have now been outlined using
06:16green. I can turn that off. I can also do things like Outline Images. You can
06:20see that images have now been outlined using a purple border.
06:27Under the Images menu, you can do a whole bunch of things. You can Disable
06:30Images to see what your website looks like in case somebody has images
06:34disabled. So I'll turn those back on.
06:37You can also do a really useful thing called the View Image Report. So when you
06:41view the image report, this generates a report of all the images used in the
06:46page, and a whole bunch of attributes that go along with them, and it shows you
06:50the image as well. So all the images are shown along with their attributes.
06:57Okay, I'm going to go ahead and close that.
06:58Then finally, there is a Validate menu. You can validate your HTML or CSS or
07:04your Links right here from within the Developer bar. So if I just choose
07:09validate HTML, it's going to go off to the W3Cs validator. You can see that
07:14this document was successfully checked as XHTML 1.0 Strict, and that's because
07:19that's the document type definition that it's using.
07:21So it's a really great feature. It's available for free from the Microsoft
07:25website. Go ahead and use the URL that I provided in the slides to download
07:29this. Again, very useful tool for anybody who is doing real world and practical
07:33web development really need to have this new toolbox.
Collapse this transcript
Debugging with Visual Web Developer
00:00Okay, the last tool that I'm going to cover is going to be the Visual Web
00:05Developer 2008 Express Edition and this is a free tool available from Microsoft
00:10and as I said earlier, this is the tool that I have been using throughout this
00:13course to and of my script and pages and browse, files and so on.
00:18Like I said, it's available for free from Microsoft, so I provided the URL in
00:22my slides so you can go directly there or you just do a search on Microsoft
00:25Visual Web Developer 2008 and this will shall come up.
00:28So what I want to focus on most in this particular example is the debugging
00:33abilities of Visual Web Developer. It's a full-fledged editor, but it also has
00:37a great debugger built-in. So just like Firebug is a great debugger available
00:41for Firefox, Visual Web Developer is a great debugger and you can use it with
00:46Internet Explorer.
00:47So couple of things you have to do differently when you are using Visual
00:50Developer as your debugger for your files. What you need to do first is open up
00:55the project you want to debug as a website and you can open any arbitrary
01:00folder as a website. So I'm just going to ahead and browse to the
01:02exercise_files and open those up.
01:05And now web developer is treating this as if it's a website. So I can go ahead
01:09and open a file and I'm going to open up the same file that we used in the
01:14Firebug debugging example. That was the TableSorting and I'm going to open up
01:19the JavaScript file that we want to debug as well.
01:23So you notice that when you open up as a website, this little green triangle
01:26right here, this is the debugger that got enabled. So to start debugging, all I
01:30need to do is click that little green arrow and it will be off and running.
01:33Before I do that, I'm going to set a break point in my JavaScript code and
01:39unlike in the Firebug example, I don't need to put a debugger statement in the
01:43code anywhere. I'm just going to go ahead and pop a break point right on this
01:47line and I do that by clicking in, little grey margin over here, next to the
01:51line that I want to put a break point on.
01:53So once I have got that set, I can go back to my HTML file and I'll click the
01:57little green arrow and we'll be off and running. Now if you get a message that
02:01pops up saying that you need to add a web.config file to your site, just go
02:05ahead and click OK, because it's just local and you don't really have to worry
02:09about that. It's not going to change your site at all. Just click OK. Also make
02:13sure in the Tools Options settings of Internet Explorer you have got the
02:17Disable Script Debugging feature disabled. You want to have Script Debugging
02:22enabled for Internet Explorer to have all this work.
02:24Okay, so we started debugging as you can see now that the break point has been
02:28hit and I'm going to go ahead and Step Over this. Now there is couple of ways
02:31you can do this. If you look under the Debug menu, you will see that just like
02:34in Firebug we have Step Into, Step Over and Step Out or you can use the
02:37function keys F11 for Step Into and F10 for Step Over and Shift+F11 for Step Out.
02:44So I'm going to go ahead and hit F10, step over this, and you can see that down
02:49here in the Locals window that the Link variable now has a value and it's set
02:54to this. Right, this is the href of the Link tag that we just got. Over here
03:00just like in Firebug it's showing the Call Stack. So it's showing me that we
03:04came from an anonymous function and we are now inside SortControls and since
03:09this is a DOM element, I can go ahead and expand it and see what's in here.
03:13I can view these properties, I can change them, if I wanted to double-click on
03:18one of these guys and change it, I can do that so I can double-click on this
03:21and change the value there, if I really wanted to. I'm not going to do that
03:24because I don't want to break anything.
03:25Now, I can go ahead and start stepping through. So I'm going to hit F10 again
03:28and F10 again, F10. Now if I get to a line with a function on it like this one,
03:33addEventHandler, I can step into this function by hitting F11. So hit F11.
03:39I'm going to step into addEventHandler. This is the same cross-browser
03:44addEventHandler that we had earlier, and to get some more room, we are going to
03:48close this guy, F10. Now to step out of here I'm just going to hit Shift+F11
03:53and that's going to drop me back right off where we stepped into it from. So we
03:57hit F10, F10 and so on.
03:59So you can see that by using the debugger feature of Visual Web Developer,
04:03you get the same kind of powerful debugging functions that you get in Firebug and
04:07in this case, you are just doing it in IE. So now you have two very powerful
04:12debugging tools available no matter which browser you happened to be using,
04:16whether it's IE or Firefox.
04:18Okay, the last thing I want to show you is a trick for using Visual Web
04:23Developer to debug any arbitrary document that happens to be live on the web.
04:30So I'm going to go ahead and run this guy, I can see everything is working.
04:35Okay, so here's what we are going to do. I'm going to close this project.
04:38I'm going to close this window. Now Visual Web Developer will only let you debug a
04:45document that was in the same process that Visual Web Developer used to launch
04:51Internet Explorer, you can't just simply attach VWD to a running instance of IE.
04:56That's a feature that's disabled in the free version of Visual Web Developer.
05:01So what you need to do is make a fake website and I'm just going to say new
05:05website. It doesn't really matter what it is and we can probably say it's an
05:08empty website. So now I have made an empty website. And again you need to make
05:13sure that in IE you have Script Debugging enabled first. So I'm going to go and
05:20click the Run button and it's going to go ahead and add that web.config for me.
05:24That's fine.
05:25All right, so now I have got my empty site running. So I'm going to go ahead
05:29and navigate to a page that I know for a fact has a problem in it and this one
05:34happens to have a problem. So because there is a bug in this page -- actually
05:39this isn't the one. This is the one right here. There we go. So you can see
05:45that when I try to go to a page that has a problem in it because I launched the
05:51browser from within Visual Web Developer, it allows me to break.
05:56So I'm just going to go ahead and say Break and now I can start debugging like
05:59I would any other problem. So if you have a website that's got a page with bugs
06:05in it, all you need to do is fake up a website using Visual Web Developer just
06:09to get the IE process running. And then once IE is running, just go ahead and
06:13navigate to the page that has the problem in it and when the problem gets hit
06:17by the debugger it will break and drop into Visual Web Developer and you can
06:21just go ahead and start debugging.
06:23Okay, well I hope that was useful for you, you should go ahead and get Visual
06:26Developer Express, the free tool from Microsoft. It's a really great debugger
06:29and this will improve your JavaScript debugging abilities at least tenfold
06:33if not more than that.
Collapse this transcript
Conclusion
Goodbye
00:00And that concludes Practical and Effective JavaScript. I hope you enjoyed
00:04yourself watching this title, hope you learned a lot. You should have
00:07everything you need to know now to go out and start building much more
00:09practical and effective JavaScript programs in your web pages.
00:13We saw how to use the Modern Event Model. We saw how to use progressive
00:16enhancement in your pages to give users a better experience, depending on what
00:20kind of capabilities they have in their browser. We saw how to use
00:23object-oriented JavaScript to create reusable pieces of code that we can
00:27evolve over time and reduce the amount of effort we need to build features and
00:31we saw using regular expressions to do much more advanced text processing.
00:35Finally, we took a look at tools that no JavaScript developer should be without
00:39in their toolbox. So go out there, make better scripts and have a great time.
Collapse this transcript


Suggested courses to watch next:

JavaScript Essential Training (5h 31m)
Simon Allardice

AJAX Essential Training (4h 22m)
Dori Smith


Are you sure you want to delete this bookmark?

cancel

Bookmark this Tutorial

Name

Description

{0} characters left

Tags

Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading
cancel

bookmark this course

{0} characters left Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading

Error:

go to playlists »

Create new playlist

name:
description:
save cancel

You must be a lynda.com member to watch this video.

Every course in the lynda.com library contains free videos that let you assess the quality of our tutorials before you subscribe—just click on the blue links to watch them. Become a member to access all 98,648 instructional videos.

start free trial learn more

If you are already an active lynda.com member, please log in to access the lynda.com library.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Access to lynda.com videos

Your organization has a limited access membership to the lynda.com library that allows access to only a specific, limited selection of courses.

You don't have access to this video.

You're logged in as an account administrator, but your membership is not active.

Contact a Training Solutions Advisor at 1 (888) 335-9632.

How to access this video.

If this course is one of your five classes, then your class currently isn't in session.

If you want to watch this video and it is not part of your class, upgrade your membership for unlimited access to the full library of 1,896 courses anytime, anywhere.

learn more upgrade

You can always watch the free content included in every course.

Questions? Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com.

You don't have access to this video.

You're logged in as an account administrator, but your membership is no longer active. You can still access reports and account information.

To reactivate your account, contact a Training Solutions Advisor at 1 1 (888) 335-9632.

Need help accessing this video?

You can't access this video from your master administrator account.

Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com for help accessing this video.


site feedback

Thanks for signing up.

We’ll send you a confirmation email shortly.


By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked