JavaScript I – Day 11
Geekwise Academy
Instructors:
Corey Shuman
Aaron Lurz
Slack Channel:
https://geekwise-js1.slack.com
Github:
https://github.com/coreyshuman/Geekwise-JavaScript-I
Lesson plans:
http://coreyshuman.github.io/Geekwise-JavaScript-I/html/
· Review Day 10 Assignment
· Review Day 10 Event Handlers
· Event Review Task
· Event Delegation
o Event Bubbling
· Objects
· Array forEach
· Array Sorting
· Discuss final touches on ToDo Application
Create a small application that adds an item to a list each time the user clicks a button. Use a global variable that is incremented on each click to give each new list item a unique name (use the incremented number). Finally, add an event handler to each item in the list so that they can be deleted when clicked. Hint: Start by having each list item alert its text when clicked. Once you have that working replace the alert with a delete.
As
we've seen so far, all of our event handlers are attached directly to the
element they work with. We attached click handlers on our li
tags to alert a movie title, etc... When this happens 1
copy of the function is created and stored for every event listener. Imagine if
we had an html list with 500 items in it. If we wanted to register a callback
for every one of the li
tags, that would store 500 copies of a callback function in memory! There is a
better way!
In order to leverage a better way of watching using event listeners, we have to first understand how events in a browser work.
The idea of event bubbling
simply means that an event bubbles up the DOM tree,
triggering the given event on every node up the DOM tree.
So if I click on a button, the click event starts at the button, then moves to its parent, then to that elements parent and so on, until it reaches the top of the document.
Here's a visual demonstration of a click bubbling up the DOM tree. Image from http://www.pageresource.com/dhtml/ryan/part4-7.html.
Let's create an example that uses event. Start with a list that has 5 items in it.
<ul id="myul">
<li>
foo
</li>
<li>
bar
</li>
<li>
baz
</li>
<li>
bleep
</li>
<li>
bloop
</li>
</ul>
Now I want to be able to click on any li
and alert the
text of that node. But instead of attaching an event listener to every li
, I'll just do
it on the ul
.
When we click on a li
,
the event will bubble up to its parent (the ul
) and the click
event handler we'll set up will fire.
document
.getElementById("myul").addEventListener("click",function
(
evt
){
console
.log(this);
console
.log(evt
);
});
Ok, so what is the this
context
in our callback? It's the ul
right? So how can we know which li
was actually
clicked on that caused the click event that bubbled to the ul
?
Let's take a closer look at the evt
object that the event handler received.
document
.getElementById("myul").addEventListener("click",function
(
evt
){
console
.log(evt
);
});
If we look closely, you'll see there is a property there
called target
. This
property on the event object will contain the node we actually clicked on.
So now let's use this new evt.target
property to get the textContent
of the li
we clicked on and alert that.
document
.getElementById("myul").addEventListener("click",function
(
evt
){
alert(
evt
.target
.textContent
);
});
So now we only have 1 event handler for click events,
which through the evt
object we
can determine which thing was actually clicked on, and do something with that.
Event delegation can single handedly reduce memory consumption of your app by great amounts if used properly.
As an additional note, events can also be "captured" by traveling down the DOM tree instead of up. You can see more examples of event bubbling and capturing here:
http://javascript.info/tutorial/bubbling-and-capturing
JavaScript objects are a variable type that is useful for
modeling real-life objects. An Object stores a collection of properties
which are themselves variables
that describe the object. Objects can also contain functions (which are known
as methods
when inside an object).
To give an example of an Object, compare it to a cup. The cup is an object with properties. Those properties describe the color, weight, material, etc… The cup can also partake in actions, which we can model using our object methods. You can pour the cup, fill the cup, wash the cup…
So now we can expand on our cup example and actually model a cup as a JavaScript Object.
// create our cup object using dot notation
var
myCup =
new
Object();
myCup.color =
"black"
;
myCup.type =
"mug"
;
myCup.status =
"full"
;
myCup.content =
"coffee"
;
In this example we have created an Object for our cup that
defines the color, type, status, and content of the cup. Note that the above
example uses dot notation to access the properties of Object myCup
. We can also use bracket notation as
shown below.
// alternate method using bracket notation
var
myCup2 = {};
myCup2[
"color"
] =
"black";
myCup2[
"type"
] =
"mug"
;
myCup2[
"status"
] =
"full"
;
myCup2[
"content"
] =
"coffee"
;
Another way to think of an Object is as a set of name:value
pairs. Each property in an Object has a name
which stores a value
. You can see this format
more obviously in this next example:
// another way to create an object as name:value pairs
var
myCup3 = {color:
"black"
, type:
"mug"
, status:
"full"
, content:
"coffee"
};
Now that we've different ways to add properties
to an Object, let's look at how to
add a method
to the Object. Remember that
a method
is just a function so we
would expect it to perform an action with or on our cup. Let's create a function
to pour the cup.
// add a pour method to the cup Object
myCup.pour =
function
pour() {
if
(
this
.status ===
"full"
) {
this
.status =
"half-full"
;
}
else
{
this
.status =
"empty"
;
this
.content =
"none"
;
}
return
this
.status;
}
Notice how we can change multiple properties within our method in a way that makes sense. Once we've poured everything out of the cup, we can change the status to empty and the content to none.
Now you try. Create a method
that will "fill" the cup.
Next add a new property
to the Object called clean
and initialize it to false
. Create a new method that will
"clean" the cup by toggling the clean property
to true
.
A very useful feature of an array is the forEach function. It's a shortcut to a for loop with the added benefit of a function closure.
The idea with a normal for loop is to create a loop that will loop N number of times. We usually combine this with an array so we can loop over the array contents. The forEach loop gets right to the point, and automatically loops over all of an array's contents.
var arr = ['a', 'b', 'c'];
arr.forEach(function (item) {
console.log(item);
});
Let's pick that apart. We first target the arr and call the forEach function. The forEach function takes one argument, the function to call on each item of the array. That callback function gets one argument, an item in the array, and it can then do something with each of those items. This might be useful to augment your ToDo Application and simplify some of the code.
We've done quite a bit with arrays up to this point, and they've proven to be a useful data structure for holding content when order matters.
One useful function we've yet to discuss is sorting an array. Arrays come with built in methods that allow for sorting an array in just about any way you want to. Let's start by taking a look at a numeric sort.
var
nums
=[4,
2,
9,
7,
3,
5,
1,
6,
8];
console
.log(nums
.sort());
Awesome, we get the array, sorted by number. Let's try a different example.
var
nums
=[100,
10,
4,
2,
9,
7,
3,
5,
1,
6,
8];
console
.log(nums
.sort());
Notice anything odd about the way that array was sorted? Here is a good example of why JavaScript sometimes can leave you scratching your head. We can see that we got something like 1, 10, 100, 2, ... Why is that?
The answer is that by default, JS will sort things in Unicode order, which gives you something like the result above. So...how can we make this act in a more sane way?
The sort function actually takes an argument that is a function. This function can do the job of determining how to sort the array, which means that you can sort in numerous ways.
The sorting function looks like this:
var
nums
=[100,
10,
4,
2,
9,
7,
3,
5,
1,
6,
8];
nums
.sort(function(
a
,b
){
//inspect a and b to determine how things should be sorted
});
So the sorting function receives two arguments, usually
aliased to a
and b
. These are two elements from the array. The sorting
functions job is to compare the two array items and determine which is larger.
The return value of the sorting function will determine if the "a"
element is sorting higher or lower than the "b" element.
It works like this:
·
If the return value of the sorting
function is a negative number, sort a
lower than b
.
·
If the return value of the sorting
function is a positive number, sort a
higher than b
.
· If the return value is 0, this signifies that the values are equal, so do not change these elements order.
So, one quick way of sorting numbers might look like:
var
nums
=[100,
10,
4,
2,
9,
7,
3,
5,
1,
6,
8];
nums
.sort(function(
a
,b
){
return
a
-b
;
});
Let's hypothetically say a = 100 and b = 10; 100 - 10 ===
90, which is a positive number, so a
would be
sorted higher than b
. If a = 10 and
b = 100, then 10 - 100 === -90, so a
would be
sorted lower than b
.
String sorting for arrays is a little nicer than numbers. You can use greater than / less than operators with strings where "a" is the lowest value and "z" is the highest value.
Try it: In your console, run "a"
< "z"
then run "z"
< "a"
. The result should
be true
then false
, because "a" is less than "z" and "z"
is not less than "a". This is what the sort function does for
strings.
Let's sort an array of strings.
var
strings
=["cherry",
"apple",
"berry"];
strings
.sort();
console
.log(strings
);
So, without much intervention on our part, an array of strings can be sorted just by calling sort on it.
This week you should be finishing up your ToDo Application. Hopefully your HTML is complete, including a checkbox to mark each item as done, an edit button for each item, and a delete button for each item. Now you should apply what you have learned about event delegation to get the checkbox and buttons functioning.