After following along with the weekend homework, we have a simple address book application that can create contacts and add, delete, and find them in an address book. Now let's start building the UI!
In the process, we'll experiment with adding dynamic elements to the DOM and learn about new concepts like event bubbling and event delegation. These are more advanced concepts that you won't be expected to apply to this section's independent project. However, you are encouraged to experiment with them, as they'll make you a better coder in the long run.
Let's get the basics of our UI up and running. We'll create an index.html
file in the top-level of our directory with the following HTML boilerplate:
<!DOCTYPE html>
<html lang="en-US">
<head>
<title></title>
</head>
<body>
</body>
</html>
Next let's fill in each section. First we'll add links to our <head>
section:
<!DOCTYPE html>
<html lang="en-US">
<head>
<link
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
crossorigin="anonymous">
<script src="js/scripts.js"></script>
<title>Address Book</title>
</head>
<body>
</body>
</html>
We've added the following, which should all be review:
<script>
tag for Bootstrap's JS if you want to implement any Bootstrap elements that are interactive. We won't include the script in the Address Book project, but you are welcome to do so in the projects you build in this course section.scripts.js
file containing our JavaScript Logic.<title>
for our page.We'll add a CSS style sheet later when we're ready to use it.
Now let's focus on the <body>
. We'll keep it simple before later adding Bootstrap classes for styling and organization:
...
<body>
<h1>Address Book</h1>
<h2>Add a Contact:</h2>
<form id="new-contact">
<label for="new-first-name">First Name</label>
<input type="text" id="new-first-name" name="new-first-name">
<label for="new-last-name">Last Name</label>
<input type="text" id="new-last-name" name="new-last-name">
<label for="new-phone-number">Phone Number</label>
<input type="text" id="new-phone-number" name="new-phone-number">
<button type="submit">Add</button>
</form>
<h2>Contacts:</h2>
<div id="contacts">
</div>
<div id="contact-details" class="hidden">
<p>First Name: <span id="first-name"></span></p>
<p>Last Name: <span id="last-name"></span></p>
<p>Phone Number: <span id="phone-number"></span></p>
</div>
</body>
...
Here we have:
A form to add new contacts, including fields for first names, last names, and phone numbers. Each field also has a corresponding <label>
.
A <div>
element with an id of contacts
, where we will add a list of Contact
s.
A contact-details
div that will eventually display the details for a specific contact when selected from the list.
Next let's add CSS. We'll create a css
subdirectory with a styles.css
file inside containing a single rule:
.hidden {
display: none;
}
This ensures the contact-details
div is hidden until we display a contact's details.
After following along with the past few lessons we should already have a scripts.js
file in a js
directory that looks like this:
// Business Logic for AddressBook ---------
function AddressBook() {
this.contacts = {};
this.currentId = 0;
}
AddressBook.prototype.addContact = function(contact) {
contact.id = this.assignId();
this.contacts[contact.id] = contact;
};
AddressBook.prototype.assignId = function() {
this.currentId += 1;
return this.currentId;
};
AddressBook.prototype.findContact = function(id) {
if (this.contacts[id] !== undefined) {
return this.contacts[id];
}
return false;
};
AddressBook.prototype.deleteContact = function(id) {
if (this.contacts[id] === undefined) {
return false;
}
delete this.contacts[id];
return true;
};
// 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;
};
Below this business logic we'll add a new section for user interface logic, denoted by another comment:
...
// User Interface Logic ---------
let addressBook = new AddressBook();
function handleFormSubmission(event) {
event.preventDefault();
const inputtedFirstName = document.querySelector("input#new-first-name").value;
const inputtedLastName = document.querySelector("input#new-last-name").value;
const inputtedPhoneNumber = document.querySelector("input#new-phone-number").value;
let newContact = new Contact(inputtedFirstName, inputtedLastName, inputtedPhoneNumber);
addressBook.addContact(newContact);
console.log(addressBook.contacts);
}
window.addEventListener("load", function (){
document.querySelector("form#new-contact").addEventListener("submit", handleFormSubmission);
});
Let's walk through this new code:
We create a new AddressBook
object named addressBook
. This is a global variable because it's declared at the 'top level' of our file. A quick reminder: while we generally want to avoid global variables, we've made an exception here to mimic a database.
At the bottom of our scripts, we create an event listener for the window
's 'load' event. The callback function we pass into window.addEventListener()
will be called when our webpage has loaded all resources and is ready to go.
Within the window
's 'load' event listener we create an event listener for the form submission event. When the form is submitted the handleFormSubmission()
function will be called. Take note that the naming convention to prefix event handler functions with handle
is very common, but it's not required to follow. The baseline here is to always name your functions descriptively, so that anyone can immediately tell what the function's purpose is in the code.
We then define the function handleFormSubmission()
above where we call it in the window
'load' event listener. In this function we:
event.preventDefault()
to prevent the refresh of the page.inputtedFirstName
, inputtedLastName
, and inputtedPhoneNumber
.Contact
object, passing in this gathered information as arguments, and saving the new Contact
object in the variable newContact
.newContact
to our AddressBook
using the AddressBook.prototype.addContact()
method.Contacts
in our AddressBook
to the console, to double-check that the new contact has been added. In the next lesson, we'll add logic for displaying contacts to the webpage.
The entire updated scripts.js
file looks like this:
// Business Logic for AddressBook ---------
function AddressBook() {
this.contacts = {};
this.currentId = 0;
}
AddressBook.prototype.addContact = function(contact) {
contact.id = this.assignId();
this.contacts[contact.id] = contact;
};
AddressBook.prototype.assignId = function() {
this.currentId += 1;
return this.currentId;
};
AddressBook.prototype.findContact = function(id) {
if (this.contacts[id] !== undefined) {
return this.contacts[id];
}
return false;
};
AddressBook.prototype.deleteContact = function(id) {
if (this.contacts[id] === undefined) {
return false;
}
delete this.contacts[id];
return true;
};
// 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 ---------
let addressBook = new AddressBook();
function handleFormSubmission(event) {
event.preventDefault();
const inputtedFirstName = document.querySelector("input#new-first-name").value;
const inputtedLastName = document.querySelector("input#new-last-name").value;
const inputtedPhoneNumber = document.querySelector("input#new-phone-number").value;
let newContact = new Contact(inputtedFirstName, inputtedLastName, inputtedPhoneNumber);
addressBook.addContact(newContact);
console.log(addressBook.contacts);
}
window.addEventListener("load", function (){
document.querySelector("form#new-contact").addEventListener("submit", handleFormSubmission);
});
We can now launch our index.html
page in the browser, fill out our form several times, and see a growing list of Contact
s logged in the console! The next step will be to actually display our contacts in the DOM. In order to do that, though, we first need to learn how to loop through object properties.
See the branch below for the code added in this lesson, including HTML, CSS, and UI Logic in our scripts.js
.