Lesson Monday

Next let's add code to display all Contacts on our page. In this lesson we'll walk through implementing the code necessary to attach the records to our unordered list of contacts. Let's jump right in.

Displaying Dynamic Contact Data

We'll start by writing an empty displayContactDetails() method below our global variable, but above our form submission code:

scripts.js
...

// User Interface Logic ---------
var addressBook = new AddressBook();

function displayContactDetails(addressBookToDisplay) {
}

$(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 inputtedPhoneNumber = $("input#new-phone-number").val();
    var newContact = new Contact(inputtedFirstName, inputtedLastName, inputtedPhoneNumber);
    addressBook.addContact(newContact);
    console.log(addressBook.contacts);
  })
})

This method will display Contact info in the DOM; hence its name. It takes an AddressBook object as an argument. Also, notice we're not plopping it directly into the block of code with our form submission listener. This is a best practice. By separating it out, we'll simplify things for ourselves in the long run.

Next let's write the rest of the method. We'll apply new best practices along the way too:

scripts.js
...

function displayContactDetails(addressBookToDisplay) {
  var contactsList = $("ul#contacts");
  var htmlForContactInfo = "";
  addressBookToDisplay.contacts.forEach(function(contact) {
    htmlForContactInfo += "<li id=" + contact.id + ">" + contact.firstName + " " + contact.lastName + "</li>";
  });
  contactsList.html(htmlForContactInfo);
};

...
  • First we save our jQuery ul#contacts element in a variable called contactsList. This is best practice because it takes jQuery time to query the DOM and find ul#contacts. Saving it in a variable prevents it from later querying the DOM again, if we eventually use the selector multiple times. This is much more efficient.

  • Next we iterate through the Contacts saved in the AddressBook provided as an argument to displayContactDetails(). We assign each Contact to a <li> with a dynamic id matching the Contact's id property. This is very important, because we can later retrieve this id stored in the <li> to use with our findContact() prototype method to locate an entire Contact object.

We could've appended each Contact to the DOM one at a time, but that's inefficient. It's much faster to concatenate all Contacts inside <li>s first, then add them to the DOM in a single .html() call, like we do here.

Let's call this new method whenever we add a new Contact. We can replace our existing console.log() call with it:

scripts.js
...

$(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 inputtedPhoneNumber = $("input#new-phone-number").val();
    var newContact = new Contact(inputtedFirstName, inputtedLastName, inputtedPhoneNumber);
    addressBook.addContact(newContact);
    displayContactDetails(addressBook);  // <--- this is the new line!
  })
})

Now each time we add a new Contact the page will update to display their first and last names. Load up the page, and try it out in the browser!

And, if we open Chrome Developer Tools and inspect elements on the page (Right-click, then select Inspect) we'll see each Contact's <li> entry has a unique id corresponding to the Contact object's automatically-assigned id property.

After following along, our updated scripts.js file looks like this:

scripts.js
// Business Logic for AddressBook ---------
function AddressBook() {
  this.contacts = [],
  this.currentId = 0
}

AddressBook.prototype.addContact = function(contact) {
  contact.id = this.assignId();
  this.contacts.push(contact);
}

AddressBook.prototype.assignId = function() {
  this.currentId += 1;
  return this.currentId;
}

AddressBook.prototype.findContact = function(id) {
  for (var i=0; i< this.contacts.length; i++) {
    if (this.contacts[i]) {
      if (this.contacts[i].id == id) {
        return this.contacts[i];
      }
    }
  };
  return false;
}

AddressBook.prototype.deleteContact = function(id) {
  for (var i=0; i< this.contacts.length; i++) {
    if (this.contacts[i]) {
      if (this.contacts[i].id == id) {
        delete this.contacts[i];
        return true;
      }
    }
  };
  return false;
}

// Business Logic for Contacts ---------
function Contact(firstName, lastName, phoneNumber) {
  this.firstName = firstName,
  this.lastName = lastName,
  this.phoneNumber = phoneNumber
}

Contact.prototype.fullName = function() {
  return this.firstName + " " + this.lastName;
}

// User Interface Logic ---------
var addressBook = new AddressBook();

function displayContactDetails(addressBookToDisplay) {
  var contactsList = $("ul#contacts");
  var htmlForContactInfo = "";
  addressBookToDisplay.contacts.forEach(function(contact) {
    htmlForContactInfo += "<li id=" + contact.id + ">" + contact.firstName + " " + contact.lastName + "</li>";
  });
  contactsList.html(htmlForContactInfo);
};

$(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 inputtedPhoneNumber = $("input#new-phone-number").val();
    var newContact = new Contact(inputtedFirstName, inputtedLastName, inputtedPhoneNumber);
    addressBook.addContact(newContact);
    displayContactDetails(addressBook);
  })
})

Best Practices Review

Let's recap some of the best practices we just used:

  1. We created a separate UI function instead of adding the code to our form submission block. This allows us to focus on writing one function at a time, and helps keep code modular.

  2. We store a jQuery selector inside a variable. That way, if we need to use the selector multiple times, jQuery only needs to query the DOM once, making code faster and more efficient.

  3. We create a list of all elements we want to append to the DOM, and add them all at once instead of one a time. This is also faster and more efficient.

You aren't expected to master these best practices just yet, but continually practice integrating them in your code throughout the course. These kinds of details separate beginning coders from more experienced ones.

In the next lesson, we'll add UI functions that will allow us to display the detailed information of an individual contact onscreen.


Example GitHub Repo for the Address Book

Best Practices


  1. Create a separate UI function instead of adding the code to the form submission block. This allows us to focus on writing one function at a time, and helps keep code modular.

  2. Store jQuery selectors inside a variable. That way, if we need to use the selector multiple times, jQuery only needs to query the DOM once, making code faster and more efficient.

  3. Create a list of all elements to append to the DOM, and add them all at once instead of one a time. This is also faster and more efficient.

Examples


Create a UI function to display contacts in an address book:

function displayContactDetails(addressBookToDisplay) {
  var contactsList = $("ul#contacts");
  var htmlForContactInfo = "";
  addressBookToDisplay.contacts.forEach(function(contact) {
    htmlForContactInfo += "<li id=" + contact.id + ">" + contact.firstName + " " + contact.lastName + "</li>";
  });
  contactsList.html(htmlForContactInfo);
};

Example GitHub Repo for the Address Book