Lesson Weekend

Now that we have a basic understanding of JavaScript objects, let's put them to work! In the next few lessons we'll build an address book application to store contact information for our friends and acquaintances. Once complete, our application will look and function something like this.

Since each contact will have multiple properties, we will use Contact JavaScript objects to encapsulate data. And since each contact will have the same properties (such as name, phone number, etc.) we can create a single Contact constructor to make many unique contacts with the same properties. This means we will have a single function that defines every property for a contact object.

Each entry in our address book (or, Contact object) should have a first name and last name. As such, we'll begin creating our Contact constructor with firstName and lastName properties, and include additional properties later on. We'll also create a prototype that retrieves a contact object's full name.

Contact Constructor

Before we begin, let's experiment in the JavaScript console:

Here's a basicContact constructor:

function Contact(first, last) {
  this.firstName = first;
  this.lastName = last;
}

Let's copy and paste this into the JavaScript console so that we can explore how this works before beginning our project:

> function Contact(first, last) { this.firstName = first; this.lastName = last; }
> var ada = new Contact("Ada", "Lovelace");
> ada.firstName
"Ada"
ada.lastName
"Lovelace"

Whenever a new Contact object is created, it is initialized with whatever first and last names we pass into the constructor as arguments. The line var ada = new Contact("Ada", "Lovelace"); creates a new Contact object by calling the Contact constructor and passing it the strings "Ada" and "Lovelace". The ada.firstName property becomes "Ada" and the ada.lastName property becomes "Lovelace".

The JavaScript console can also display a summary of the object, which is useful for debugging:

> ada
Contact {firstName: "Ada", lastName: "Lovelace"}

Here, we can see that the variable ada holds an object that is an instance of the Contact type and that it has two properties - firstName with the value "Ada" and lastName with the value "Lovelace".

Now that we've experimented with our Contact constructor, let's begin building our address book. First, we'll need to set up our JavaScript project directory. The image below details all files that will be used in our application:

Address book project directory

Note: Because we will continue to build on this same address book project over the next few lessons, example repos will be linked throughout for reference. These are simply a snapshot of the project at the given point in development; you're not required to do anything with these repos.

Example GitHub Address Book Repo with Initial Files

Now, let's place our Contact constructor into scripts.js :

js/scripts.js
function Contact(first, last) {
  this.firstName = first;
  this.lastName = last;
}

User Interface Logic

Now that our JavaScript Contact constructor is in place, let's incorporate it into a web page, or user interface. First we'll create a basic form that allows users to enter a contact's first and last names. Each new contact created through this form will be added to an ongoing list of all contacts.

We'll begin by adding this form, and a place to append newly-created contacts to:

address-book.html
<!DOCTYPE html>
<html>
  <head>
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css">
    <link href="css/styles.css" rel="stylesheet" type="text/css">
    <script src="js/jquery-1.12.0.js"></script>
    <script src="js/scripts.js"></script>
    <title>Address book</title>
  </head>
  <body>
    <div class="container">
      <h1>Address book</h1>

      <div class="row">
        <div class="col-md-6">
          <h2>Add a contact:</h2>
          <form id="new-contact">
            <div class="form-group">
              <label for="new-first-name">First name</label>
              <input type="text" class="form-control" id="new-first-name">
            </div>
            <div class="form-group">
              <label for="new-last-name">Last name</label>
              <input type="text" class="form-control" id="new-last-name">
            </div>

            <button type="submit" class="btn">Add</button>
          </form>

          <h2>Contacts:</h2>
          <ul id="contacts">

          </ul>
        </div>
      </div>
    </div>
  </body>
</html>

Here, the empty <ul> with the id of "contacts" is where each new contact will be appended.

Next, we need some JavaScript in our jQuery callback that will collect the user input from the form, and assign it to variables. We'll use the input to create new Contact objects with our constructor. Then, we'll append the new objects to our list for display to the user.

js/scripts.js
//business logic
function Contact(first, last) {
  this.firstName = first;
  this.lastName = last;
}

// user interface logic
$(document).ready(function() {
  $("form#new-contact").submit(function(event) {
    event.preventDefault();

    var inputtedFirstName = $("input#new-first-name").val();
    var inputtedLastName = $("input#new-last-name").val();

    var newContact = new Contact(inputtedFirstName, inputtedLastName);

    $("ul#contacts").append("<li><span class='contact'>" + newContact.firstName + "</span></li>");

    $("input#new-first-name").val("");
    $("input#new-last-name").val("");
  });
});

Now, if we fire up our web page, each time we add a contact it is appended to the contact list. The line var newContact = new Contact(inputtedFirstName, inputtedLastName) creates a new Contact object by calling the Contact constructor and passing it the inputted data. The variable newContact now refers to that newly created contact object, which knows its own firstName and lastName.

Example GitHub addressBook Repo

What we've developed so far could be accomplished without objects and just jQuery. Let's add another feature to our page that better illustrates how objects make a difference in managing and displaying data. When a user clicks on a contact in the list, they will see the contact's first and last names in a div to the right of our form.

First, we'll update our HTML to add the <div> where the contact details will be shown. (This will be a second column, so it should go inside the row div but after the closing of the existing col-md-6 div.):

address-book.html
<div class="col-md-6">
  <div id="show-contact">
    <h2></h2>

    <p>First name: <span class="first-name"></span></p>
    <p>Last name: <span class="last-name"></span></p>
  </div>
</div>

We'll hide the "show" area at first, and add a class to make some elements look clickable:

css/styles.css
#show-contact {
  display: none;
}

.contact {
  cursor: pointer;
  color: #0088cc;
}

.contact:hover {
  text-decoration: underline;
}

Inside our form submit callback, after the code that appends the new contact to the list, we'll add this JavaScript to show the contact information when it is clicked:

js/scripts.js
$(".contact").last().click(function() {
  $("#show-contact").show();
  $("#show-contact h2").text(newContact.firstName);
  $(".first-name").text(newContact.firstName);
  $(".last-name").text(newContact.lastName);
});

If we didn't add last() to $(".contact"), each time a new contact was added, every element with the contact class would show the information of the most recently added contact on click. By adding last(), we only bind the event to most recently-inserted contact.

Can you imagine trying to keep track of everything on this page using just jQuery? Whew!

Example GitHub addressBook Repo at this point

Examples


address-book.html
<!DOCTYPE html>
<html>
  <head>
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css">
    <link href="css/styles.css" rel="stylesheet" type="text/css">
    <script src="js/jquery-1.12.0.js"></script>
    <script src="js/scripts.js"></script>
    <title>Address book</title>
  </head>
  <body>
    <div class="container">
      <h1>Address book</h1>

      <div class="row">
        <div class="col-md-6">
          <h2>Add a contact:</h2>
          <form id="new-contact">
            <div class="form-group">
              <label for="new-first-name">First name</label>
              <input type="text" class="form-control" id="new-first-name">
            </div>
            <div class="form-group">
              <label for="new-last-name">Last name</label>
              <input type="text" class="form-control" id="new-last-name">
            </div>

            <button type="submit" class="btn">Add</button>
          </form>

          <h2>Contacts:</h2>
          <ul id="contacts">

          </ul>
        </div>
        <div class="col-md-6">
          <div id="show-contact">
            <h2></h2>

            <p>First name: <span class="first-name"></span></p>
            <p>Last name: <span class="last-name"></span></p>
          </div>
        </div>        
      </div>
    </div>
  </body>
</html>
css/styles.css
#show-contact {
  display: none;
}

.contact {
  cursor: pointer;
  color: #0088cc;
}

.contact:hover {
  text-decoration: underline;
}
js/scripts.js
//business logic
function Contact(first, last) {
  this.firstName = first;
  this.lastName = last;
}

// user interface logic
$(document).ready(function() {
  $("form#new-contact").submit(function(event) {
    event.preventDefault();

    var inputtedFirstName = $("input#new-first-name").val();
    var inputtedLastName = $("input#new-last-name").val();

    var newContact = new Contact(inputtedFirstName, inputtedLastName);

    $("ul#contacts").append("<li><span class='contact'>" + newContact.firstName + "</span></li>");

    $(".contact").last().click(function() {
      $("#show-contact").show();
      $("#show-contact h2").text(newContact.firstName);
      $(".first-name").text(newContact.firstName);
      $(".last-name").text(newContact.lastName);
    });

    $("input#new-first-name").val("");
    $("input#new-last-name").val("");
  });
});