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/

 


 

Today’s Topics

·        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


Event Review Task

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.


Event Listeners

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!

Event Bubbling

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

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.

 


Array forEach Method

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.

 


Sorting Arrays

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.

Array String Sorting

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.

 


Assignment

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.