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