DEV Community

william-luck
william-luck

Posted on

Navigating the JavaScript Event Object

Background:

I just completed phase 1 of Flatiron's Software Engineering Flex program (I was supposed to complete this phase a few weeks ago, but that's the beauty of the flex program). I created a single-page application to keep track of those harder-to-realize accomplishments. The main idea is quite simple: complete tasks, level up corresponding skills, and earn rewards. A task log is located underneath the primary game bar to keep track of tasks completed:
Image description

Most of this functionality was achieved with the help of event listeners, namely click, submit, and keydown. I relied heavily on the event object to manipulate the DOM and get my application moving the way I wanted it to.

What is the event object?

From my own understanding, the event object is an object created once you satisfy the condition of the event listener. This event object is automatically passed into callback function, and you can access multiple points of useful information through that event object.

In the callback function itself, define a parameter to receive the event object. The name of the parameter can be really be anything, but by convention and just for ease of use, it's typical to name this parameter "event", or just simply "e". When working with the event object, I find it helpful to just console log the event at the start to remind myself of what I can do with it:
document.addEventListener('click', e => console.log(e))

Viewing the console, you get a seemingly endless amount of properties, with nested objects under certain keys:
Image description

But of course, the event object generated by clicking on a random location on the page does not tell you much (well it does, but there's no information I'm concerned with at this point). Adding event listeners to specific elements on the page gives much more relevant information to play around with.

How I used the event object in my project

For my project, I was primarily concerned with the information in the event object under e.target. I was looking for the value of the ID attribute in the event object, which I defined in my HTML:

<button class='task-button' id="self-comp-1" >Took a break when I needed to</button><br/>
<button class='task-button' id="self-comp-2" >Used positive affirmations</button><br/>
<button class='task-button' id="pers-1">Had an 'aha!' moment </button><br/>
<button class='task-button' id="pers-2">All lab tests passing</button><br/>
<button class='task-button' id="gh-1">Coded along during a lesson</button><br/>
<button class='task-button' id="gh-2">Refactored code</button><br/>
<button class='task-button' id="supp-1">Received / gave support on Slack</button><br/>
<button class='task-button' id="supp-2">Paired with a technical coach</button><br/>
Enter fullscreen mode Exit fullscreen mode

Using a for loop, I added a "click" event listener to each of eight task buttons on my application. In my callback function, I made use of a series of conditional statements to check the ID of the button that was clicked. If I click on the first button labeled "took a break when I needed to" e.target.id evaluates to "self-comp-1", and a series of functions will execute from that point to update the corresponding skill of self compassion:

for (const node of taskButtons) {
    node.addEventListener('click', e => {
        if ((e.target.id === 'self-comp-1') || (e.target.id === 'self-comp-2')) {
            if (selfCompPercentage < 100) {
                selfCompPercentage = updatePercentage(selfCompPercentageNode, selfCompPercentage, ' - Self Compassion');
                updateProgressBar(selfCompProgressBar, selfCompPercentage);
                addTaskCompleted(e);
            }
Enter fullscreen mode Exit fullscreen mode

In the last line of the above code block, I passed the event object to another function, addTaskCompleted(e), which updates the task log at the bottom of the page. I needed to do this because I needed to list the text contained in the button that was clicked by the user, like so:
Image description

Using the same event object that was created when I clicked on the button, I first declared a variable completedTask to create an element to store the name of the task. And to use the event object passed into the function, I set the textContent of the completedTask to e.target.textContent, which corresponds with the text inside the button originally clicked. Lastly, I added the new element to a completedTasksContainer:

function addTaskCompleted(e) {

    const completedTask = document.createElement('p')
    completedTask.textContent = e.target.textContent;
    completedTasksContainer.appendChild(completedTask)
Enter fullscreen mode Exit fullscreen mode

Also in the task log is an ability to add a comment, which also uses an event listener and a separate event object, as part of a 'submit' event. I created a form with a comment bar and a submit button, and then added an event listener upon submission of the simple form, with its own callback function:

// creates form next to the completed task
    const inputForm = document.createElement('form')
    inputForm.id = 'input-form'
    completedTask.appendChild(inputForm)

    // Adds comment bar
    const inputText = document.createElement('input')
    inputText.type = 'text'
    inputText.value = ''
    inputText.placeholder = 'Add comment..'
    inputText.id = 'comment'
    inputForm.appendChild(inputText)

    // Adds submit button 
    const submitButton = document.createElement('input')
    submitButton.type = 'submit'
    submitButton.name = 'submit'
    submitButton.value = 'Add'
    inputForm.appendChild(submitButton)

    // Adds comment to task completed upon submission of form
    inputForm.addEventListener('submit', addCommentToTask)    
Enter fullscreen mode Exit fullscreen mode

When adding the comment bar itself, the most important thing to note here is inputText.id = 'comment'. This allows me to access the text that was entered in the form in my callback function, once again with e.target, and add that text as a bullet point under the completed task:

function addCommentToTask(e) {

    e.preventDefault()

    const comment = e.target.comment.value
    const completedTask = e.target.parentNode  

    e.target.remove()

    const commentNode = document.createElement('ul')
    const commentText = document.createElement('li')
    commentNode.appendChild(commentText)

    commentText.textContent = `Comment: ${comment}`

    completedTask.appendChild(commentNode)
  }  
Enter fullscreen mode Exit fullscreen mode

A few things to note here:
e.preventDefault() prevents the page from refreshing upon submission of the form.
const comment = e.target.comment.value stores the value of the inputted text in a comment variable, using the ID of the comment bar itself.
const completedTask = e.target.parentNode saves a reference to the task completed, to use a header for an bullet point
e.target.remove() removes the comment bar and submit button from the task log.

After adding an unordered list bullet point, I set the text content of the bullet point to the comment variable with some string interpolation:

commentText.textContent = `Comment: ${comment}`
Enter fullscreen mode Exit fullscreen mode

Image description

The third and final event object I worked with was one created by a 'keydown' event. Upon reaching 100% in a skill, a function is called to display an emoji award. I implemented a completely useless but fun feature that allows you to rotate the axe awarded to the user upon completion of the persistence skill. The axe can be rotated plus or minus 45 degrees, depending on whether the left or right arrow is pressed down. To do this, I added a 'keydown' listener to the window (not to the axe itself, because I want the user to be able to rotate the axe at all times if the user has last clicked on the window itself):

function displayAward(node) {
    rewardsTile.textContent = "Earned rewards:"

    if (node.id === 'self-comp-percentage') {
        addHeart();
    } else if (node.id === 'pers-percentage') {
        addAxe();
        window.addEventListener('keydown', rotateAxe)
Enter fullscreen mode Exit fullscreen mode

For 'keydown' events, a different event object is created, which includes the key that was pressed down as a property. Similar to the way I console logged the event object in response to the 'click' event, console logging the event object here leads me toward some conditional logic to use:
Image description

Notice the key: and "ArrowLeft" property. Along with the event object automatically passed into the callback function, in which I use 'e' as a parameter in the callback function itself, I toyed with e.key to determine which direction the axe should rotate, using conditional logic:

function rotateAxe(e) {
    const axeNode = document.getElementById('axe')

    if (e.key === 'ArrowLeft') {
        axeRotation-=45
    } else if (e.key === 'ArrowRight') {
        axeRotation+=45
    }

    axeNode.style.transform = `rotate(${axeRotation}deg)`
}
Enter fullscreen mode Exit fullscreen mode

Final Note

Event objects are confusing. When I was first introduced to this topic, I couldn't wrap my head around how an object was automatically created and passed into callback functions. How was it passed into the callback function if i didn't explicitly pass it in? Why call it 'e' or 'event'? What is all this information dump that I have to work with? What else can I use in e.target? These questions are okay, and to not have immediate answers to them is more than okay. I did learn a lot of technical mumbo jumbo through this mini-project, but most importantly, I learned to not be intimidated by the questions that lead to other questions.

Top comments (0)