MVC JavaScript Tutorial using ES6 Class – Part 02

   Raja Tamil • Dec 4 •

This is the second part of Learn to build Object-Oriented JavaScript App using ES6 Classes series. You can check it the first part in here . In the whole series, I am building an Address Book 📕 App to demonstrate concepts like Object-orientation with ES6, MVC and other best practices when building a JavaScript-based application.

Here is the Address Book App Series

01 Address Book – Get All Contacts

02 Address Book – Get a contact

03 Address Book – Add a contact

04 Address Book – Remove a contact

05 Address Book – Edit a contact

What’s covered in this article?

  • how to add a click event to each contact list item.
  • how to show the detailed contact data on the right which is details module view when li is clicked.
  • how to show the first contact item on the details module view on load by reusing a method as well as the active state.
  • how to get the active state when list item clicked.

Let’s add the contact details module HTML code in index.html file.

<!-- contact item details module -- > 
<section> 
   <div id="contact-item-details">
      loading...
   </div> 
</section>

Then, go back to app.js and add an Event listener to <li> element inside renderContactListModule() method before appending <li> to <ul> on the AddressBookView class.

$li.addEventListener("click", this.renderContactDetailsModule);

As you can see, when <li> is clicked, renderContactDetailsModule() method will be invoked. Let’s create this method inside AddressBookView class as well.

renderContactDetailsModule(e) {
  // code goes here
}

Inside renderContactDetailsModule() method, I am going to get the selected index value using the parameter (e).

let selectedIndex = null;

if (typeof e === 'object') {
   e.stopPropagation();
   selectedIndex = this.getAttribute('data-index')
} else {
   selectedIndex = e;
}

I have declared a variable selectedIndex and set to null as it’s initial value. This variable will hold the selected index value later.

Next, I have an if condition in which I use typeof method to determine how renderContactDetailsModule() being invoked. If renderContactDetailsModule() is invoked by a click event, e would be an object. In that case, I can get the selected li index value from it’s data-index attribute which is added to each li on the renderContactListModule() method and assign to selectedIndex.

If e parameter is an object, we need to use e.stopPropagation() in order to avoid event bubbling.

Note: e.stopPropagation() will prevent parent click event when child clicks event trigger. Later we will be adding a couple of child elements like edit and delete buttons inside li. At that time, we do not want to parent click event trigger (li) when we click the child click event (edit button).

if e is not an object, we can simply assign the value of e to selectedIndex as it would be an integer. we will see later where we can call this method by passing an index value as an argument.
Let’s add the getContact() method to our AddressBookCtrl class.

// AddressBookCtrl class

 getContact(index) {
    return contactsData[index];
}

getContact() method will receive an index number as a parameter and returns a single contact object from the contactsData array based on the index value that we pass as an argument.

Now we can use getContact() inside the renderContactDetailsModule() method in order to get the selected contact object by passing the selectedIndex.

const selectedItem = addressBookApp.getContact(selectedIndex);

Next, Now I would need to get the contact details module and cache it.

 const $ContactItemUI = document.getElementById('contact-item-details');

Finally, assign the formatted string to the DOM element using its innerHTML property. As you can see I use some of the ES6 features. One is backtic (`) which is used beginning and ending of the string that allows creating multi line string. Another one is ${} format allows to add variables inside a string aka string interpolation.

$ContactItemUI.innerHTML = `${selectedItem['fname']} <br> ${selectedItem['lname']} <br> ${selectedItem['phone']} <br> ${selectedItem['email']}`;

Let’s add some CSS code in the style.css file for contact details module.

/* Contact Item Details Module */
#contact-item-details {
    float: left;
    width: 200px;
    background: #333;
    overflow: auto;
    color: white;
    padding: 10px;
    margin-left: 1px;
}

At this stage, you will be able to see the details module data on the right when li element is clicked. However, I want to show the first index content item on the details module on load.

To do that, I am going to invoke renderContactDetailsModule() method (with an arugment 0 which would be the first contact item) inside init() method on the AddressBookView class

this.renderContactDetailsModule(0);

li Active State

Let’s add a CSS class .active in the style.css file.

li:hover, .active {
    background: rgba(0, 0, 0, 0.5);
}

As you can see I have added .active class to an existing CSS rule separated by a comma.

Let’s go back to app.js and declare hightlightCurrentListItem() method inside AddressBookView class. This method will take a selectedIndex value as a parameter. Then, get an array of li DOM elements using document.getElementByClassName and store them into $ContactListItems. After that, loop through the DOM elements and remove the .active class from each li element if there is one. Finally, add the .active class to the clicked li element which can be determined using selectedIndex value on the $ContactListItems DOM array.

hightlightCurrentListItem(selectedIndex) {
  const $ContactListItems = document.getElementsByClassName('contact-list-item');
  for (let i = 0, len = $ContactListItems.length; i < len; i++) {
    $ContactListItems[i].classList.remove('active');
  }
  $ContactListItems[selectedIndex].classList.add("active")
}

Let’s invoke hightlightCurrentListItem() method inside renderContactDetailsModule() by passing selectedIndex varaible as an argument.

That’s it.

At this stage,
1. The first list item from the Contact List Module is selected and has an active state as well.
2. The first contact item data will be shown on the contact details module on the right.
3. Contact list item can be clicked and everything should work as expected like the screenshot.

Sharing is caring!