The Complete Guide to Becoming a Web Developer: Part 3

the-complete-guide-to-becoming-a-web-developer:-part-3

Hello there, web development enthusiasts! If you’ve ever built a website, you’ve interacted with the Document Object Model (DOM). But what exactly is the DOM, and why is it so crucial in web development? Buckle up, because we’re about to dive deep into the fascinating world of the DOM!

If you’re new here you can start with part 1 and part 2.

  • Introduction
  • Section 1: Understanding the DOM

    • What is the DOM?
    • How Does the DOM Work?
    • The Role of the DOM in JavaScript
  • Section 2: Selecting Elements

    • querySelector
    • querySelectorAll
  • Section 3: DOM Most Important Properties & Methods

    • classList
    • getAttribute() and setAttribute()
    • appendChild(), append(), and prepend()
    • removeChild() and remove()
    • createElement, innerText, textContent, and innerHTML
    • value, parentElement, children, nextSibling, previousSibling, and style
  • Section 4: Event Handling and Most Common Events in JavaScript

    • What is Event Handling?
    • Common JavaScript Events

      • Clicks
      • Drags and Drops
      • Hovers
      • Scrolls
      • Form Submission
      • Key Presses
      • Focus/Blur
      • Double Click
  • Section 5: Asynchronous JavaScript and the DOM
  • Section 6: Common Pitfalls in DOM Manipulation

    • Pitfall 1: Not Waiting for the DOM to Load
    • Pitfall 2: Overusing innerHTML
    • Pitfall 3: Forgetting That NodeList Is Not an Array
    • Pitfall 4: Not Properly Handling Event Propagation
  • Section 7: Building a Simple To-Do List Project

    • Step 1: Setting Up the HTML
    • Step 2: Adding Tasks
    • Step 3: Marking Tasks as Completed
    • Step 4: Removing Tasks
    • Step 5: Add Some Style
  • Conclusion
  • Additional Resources

Introduction

The DOM is like the backbone of your web page. It’s a programming interface that allows your web page to come to life, interact with users, and change dynamically. When you load a web page, the browser creates the DOM of that page, which is essentially an object-oriented representation of the web page’s structure.

Think of the DOM as a tree-like structure where each branch ends in a node, and each node contains objects. These objects are parts of your webpage like HTML tags, text content, links, images, etc. The DOM allows JavaScript to access and manipulate these objects, change their properties, react to events, and even create new elements and attributes.

Understanding the DOM is fundamental to web development because it’s the bridge between your HTML/CSS and JavaScript. Without the DOM, your JavaScript code wouldn’t be able to interact with your web page’s content and structure.

Section 1: Understanding the DOM

Welcome to the first section of our deep dive into the DOM! Now that we’ve covered the basics, let’s roll up our sleeves and get into the nitty-gritty of what the DOM is, how it works, and its role in JavaScript.

What is the DOM?

The Document Object Model, or DOM, is a programming interface for HTML and XML documents. It represents the structure of a document in a way that’s easy for programming languages like JavaScript to interact with. The DOM transforms your document into an object-oriented hierarchy or a “tree” of nodes. These nodes are objects that represent parts of the document, such as elements, attributes, and text.

Imagine a family tree. You have the grandparents at the top (the root node), their children below them (child nodes), and their grandchildren below them (leaf nodes). Similarly, in the DOM tree, the document object is the root node, elements like and are child nodes, and the elements and text inside them are leaf nodes.

How Does the DOM Work?

When you load a web page, the browser fetches the HTML and parses it, creating the DOM. This DOM is stored in the browser’s memory, not as a string, but as a set of interconnected objects with properties and methods.

Let’s take a look at a simple HTML document:




    My Web Page


    

Welcome to my web page!

This is a paragraph.

On the other hand, the browser would create a DOM that looks something like this:

document
|-- html
    |-- head
        |-- title
            |-- "My Web Page"
    |-- body
        |-- h1
            |-- "Welcome to my web page!"
        |-- p
            |-- "This is a paragraph."

This tree-like structure is what JavaScript interacts with. It can access any node, change its contents, apply styles, add or remove nodes, and so on. For instance, if you want to change the text inside the

tag or you can select the node and add a new child node to it. You do many things and you use JavaScript to select these nodes in the DOM and manipulate its contents.

The Role of the DOM in JavaScript

The DOM is the meeting point between HTML and JavaScript. It’s what allows JavaScript to interact with the HTML, changing the document’s structure, content, and styling on the fly.

Without the DOM, your JavaScript code would have no way of accessing or manipulating the HTML. You wouldn’t be able to respond to user events, update the content dynamically, or create interactive web experiences.

In other words, the DOM is what turns your static HTML document into a dynamic, interactive web page. It’s the magic behind every JavaScript-powered website or web app you’ve ever used.

Section 2: Selecting Elements

Alright, now that we’ve got a solid understanding of what the DOM is, let’s get our hands dirty and start interacting with it. The first step in DOM manipulation is selecting the elements you want to work with, and that’s where querySelector and querySelectorAll come into play.

querySelector

querySelector is a powerful method that allows you to select the first element that matches a specified CSS selector(s) in the document. It’s like a Swiss Army knife for DOM selection. You can use it to select elements by their tag name, class, ID, attribute, and more.

Here’s how it works:

let element = document.querySelector(selector);

The selector is a string containing one or more CSS selectors separated by commas. querySelector returns the first element that matches any of the specified selectors. If no matches are found, it returns null.

Let’s say we have the following HTML:

Hello, World!

Welcome to my web page.

Here’s how you can use querySelector to select these above elements:

let title = document.querySelector('#title'); // selects the element with the ID "title"
let text = document.querySelector('.text'); // selects the element with the class "text"
let div = document.querySelector('div'); // selects the first 
element

querySelectorAll

While querySelector returns the first matching element, querySelectorAll returns a NodeList (think of it as a collection) of all elements in the document that match the specified CSS selector(s).

Here’s how you can use it:

let elements = document.querySelectorAll(selector);

Again, selector is a string containing one or more CSS selectors separated by commas. querySelectorAll returns a NodeList of all elements that match any of the specified selectors. If no matches are found, it returns an empty NodeList.

Using the same HTML as before, here’s how you can use querySelectorAll:

let divs = document.querySelectorAll('div'); // selects all 
elements let elements = document.querySelectorAll('.text, #title'); // selects all elements with the class "text" and the ID "title"

Remember, querySelectorAll returns a NodeList, not an array. While you can use some array methods on a NodeList (like forEach), others (like map and filter) are not available. If you need to use these methods, you can convert the NodeList to an array using Array.from().

And there you have it! You now know how to select elements in the DOM using querySelector and querySelectorAll. These methods are incredibly powerful and versatile, and they’re the foundation of all DOM manipulation. So go ahead, start selecting elements and playing around with them.

Section 3: DOM Most Important Properties & Methods

Welcome to the heart of DOM manipulation: properties and methods. Now that we know how to select elements, it’s time to learn how to interact with them. In this section, we’ll explore a variety of properties and methods that allow us to read, change, add, and remove elements and their content. Let’s dive in!

classList

The classList property returns a live DOMTokenList collection of the class attributes of the element. This property is useful for adding, removing and toggling CSS classes on an element.

let element = document.querySelector('#myElement');
element.classList.add('new-class'); // adds 'new-class' to the element
element.classList.remove('new-class'); // removes 'new-class' from the element
element.classList.toggle('new-class'); // toggles 'new-class'

getAttribute() and setAttribute()

getAttribute() returns the value of a specified attribute on the element. setAttribute() sets the value of an attribute on the specified element.

let link = document.querySelector('a');
let href = link.getAttribute('href'); // gets the href attribute
link.setAttribute('href', 'https://www.example.com'); // sets the href attribute

appendChild(), append(), and prepend()

appendChild() adds a node to the end of the list of children of a specified parent node. append() and prepend() do the same but allow you to add multiple nodes, and they also accept strings to be inserted as text nodes.

let newElement = document.createElement('div');
document.body.appendChild(newElement); // appends newElement to the body

let textNode = document.createTextNode('Hello, World!');
newElement.append(textNode, ' Welcome!'); // appends two nodes to newElement

newElement.prepend('Greetings! '); // prepends a text node to newElement

removeChild() and remove()

removeChild() removes a child node from the DOM and returns the removed node. remove() removes the current node from the DOM.

let element = document.querySelector('#myElement');
document.body.removeChild(element); // removes element from the body

element.remove(); // removes element

createElement, innerText, textContent, and innerHTML

createElement() creates a new element node. innerText and textContent get or set the text content of a node and its descendants. innerHTML gets or sets the HTML content (inner HTML) of an element.

let newElement = document.createElement('div'); // creates a new 
element newElement.innerText = 'Hello, World!'; // sets the text content console.log(newElement.textContent); // gets the text content newElement.innerHTML = 'Hello, World!'; // sets the HTML content

value, parentElement, children, nextSibling, previousSibling, and style

value gets or sets the value of the value attribute of a text field. parentElement returns the parent element of the specified element. children returns a live HTMLCollection of child elements. nextSibling and previousSibling return the next and previous sibling of the node in the tree, or null if there are no siblings. style gets or sets the inline style of an element.

let input = document.querySelector('input');
input.value = 'Hello, World!'; // sets the value

let parent = element.parentElement; // gets the parent element
let children = element.children; // gets the child elements

let next = element.nextSibling; // gets the next sibling
let previous = element.previousSibling

Section 4: Event Handling and Most Common Events in JavaScript

Welcome to the exciting world of event handling in JavaScript! This is where your web pages truly come to life, responding to user interactions in real time. From simple clicks to complex drags and drops, JavaScript events are the heart of interactive web experiences. Let’s dive in!

What is Event Handling?

In JavaScript, an event is a signal that something has happened. This could be a user action, like clicking a button or submitting a form, or a browser action, like loading a page or resizing a window.

Event handling is the process of setting up listeners on elements that respond to these events. When an event occurs, the listener executes a JavaScript function, known as an event handler.

Event handling is crucial in JavaScript because it allows your web pages to respond to user interactions and create dynamic, interactive experiences.

Common JavaScript Events

Let’s take a look at some common JavaScript events and how to handle them.

Clicks

The click event fires when a user clicks an element.

let button = document.querySelector('button');
button.addEventListener('click', function() {
    console.log('Button clicked!');
});

Drags and Drops

The dragstart, dragover, and drop events are used to create drag and drop functionality.

let draggable = document.querySelector('.draggable');
let dropzone = document.querySelector('.dropzone');

draggable.addEventListener('dragstart', function(event) {
    event.dataTransfer.setData('text/plain', draggable.id);
});

dropzone.addEventListener('dragover', function(event) {
    event.preventDefault(); // prevent default to allow drop
});

dropzone.addEventListener('drop', function(event) {
    event.preventDefault(); // prevent default action (open as link for some elements)
    let id = event.dataTransfer.getData('text');
    let draggable = document.getElementById(id);
    dropzone.appendChild(draggable);
});

Hovers

The mouseover and mouseout events fire when the mouse pointer enters and leaves an element, respectively.

let element = document.querySelector('#myElement');
element.addEventListener('mouseover', function() {
    element.style.backgroundColor = 'yellow';
});
element.addEventListener('mouseout', function() {
    element.style.backgroundColor = '';
});

Scrolls

The scroll event fires when an element’s scrollbar is being scrolled.

window.addEventListener('scroll', function() {
    console.log('Scrolling!');
});

Form Submission

The submit event fires when a form is submitted.

let form = document.querySelector('form');
form.addEventListener('submit', function(event) {
    event.preventDefault(); // prevent form from submitting normally
    console.log('Form submitted!');
});

Key Presses

The keydown, keypress, and keyup events fire when a user is pressing or releasing a key.

window.addEventListener('keydown', function(event) {
    console.log('Key pressed: ' + event.key);
});

Focus/Blur

The focus and blur events fire when an element gets or loses focus.

let input = document.querySelector('input');
input.addEventListener('focus', function() {
    console.log('Input focused!');
});
input.addEventListener('blur', function() {
    console.log('Input blurred!');
});

Double Click

The dblclick event fires when an element is double-clicked.

let button = document.querySelector('button');
button.addEventListener('dblclick',

Section 5: Asynchronous JavaScript and the DOM

As we near the end of our deep dive into the DOM, let’s take a moment to peek into the future. Specifically, let’s talk about asynchronous JavaScript and how it interacts with the DOM. This is a vast topic that deserves its own series of articles, but we’ll touch on it briefly here to give you a taste of what’s to come.

In JavaScript, most operations are synchronous, meaning they block further execution until they’re finished. However, certain operations, like fetching data from a server or setting a timer, are asynchronous. They’re initiated now, but they finish later, allowing the rest of your code to continue running in the meantime.

Asynchronous JavaScript is crucial for creating smooth, responsive web experiences. It allows your web page to stay interactive even when it’s performing time-consuming tasks, like loading data or images.

Here’s a simple example of asynchronous JavaScript in action:

console.log('Fetching data...');

fetch('https://api.example.com/data')
    .then(response => response.json())
    .then(data => {
        console.log('Data fetched!');
        // Now you can use the data to update the DOM
    });

console.log('This will run before the data is fetched!');

In this example, the fetch function returns a Promise, which is a placeholder for the future result of an operation. The then method is used to schedule callbacks to be run when the Promise is fulfilled, or in other words, when the data is fetched.

This is just the tip of the iceberg when it comes to asynchronous JavaScript. There’s so much more to learn, including callbacks, Promises, async/await, and more. But don’t worry, we’ll cover all of that and more in future articles. For now, just know that asynchronous JavaScript is a powerful tool for creating dynamic, interactive web experiences, and it plays a crucial role in DOM manipulation.

Stay tuned for more, and keep practicing what you’ve learned so far. You’re well on your way to becoming a DOM manipulation master!

Section 6: Common Pitfalls in DOM Manipulation

Alright, we’ve covered a lot of ground so far. We’ve learned what the DOM is, how to select elements, and how to use properties and methods to manipulate those elements. Now, it’s time to talk about some common pitfalls in DOM manipulation. Even experienced developers can fall into these traps, so let’s shine a light on them and learn how to avoid them.

Pitfall 1: Not Waiting for the DOM to Load

One of the most common mistakes is trying to manipulate the DOM before it’s fully loaded. If your JavaScript runs before the HTML is parsed, it won’t be able to find the elements it’s supposed to interact with.

To avoid this, you can use the DOMContentLoaded event, which fires when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.

document.addEventListener('DOMContentLoaded', function() {
    // Your code here
});

Pitfall 2: Overusing innerHTML

While innerHTML is a powerful property that allows you to get or set the HTML content of an element, it can be a source of performance issues and security vulnerabilities.

Every time you use innerHTML, the browser has to parse the new HTML string into a DOM tree, which can be slow for large amounts of HTML. It also exposes you to cross-site scripting (XSS) attacks if you’re not careful with user input.

As a best practice, use textContent or innerText when dealing with text, and createElement, appendChild, and other DOM methods when creating new elements.

Pitfall 3: Forgetting That NodeList Is Not an Array

When you use querySelectorAll, it returns a NodeList, which is an array-like object but not an actual array. This can lead to confusion when you try to use array methods like map, filter, or reduce on a NodeList and get a TypeError.

To avoid this, you can convert a NodeList to an array using Array.from() or the spread operator (...).

let elements = document.querySelectorAll('div');
let elementsArray = Array.from(elements); // or [...elements]

Pitfall 4: Not Properly Handling Event Propagation

JavaScript events propagate, meaning they start from the deepest element (the target) and then bubble up to the root of the tree. If you’re not careful, an event handler on a parent element might fire when you interact with a child element.

To prevent this, you can use event.stopPropagation() in your event handler. However, use it sparingly, as it can make your code harder to debug and understand.

element.addEventListener('click', function(event) {
    event.stopPropagation();
    // Your code here
});

Remember, everyone makes mistakes, and that’s how we learn. The key is to understand these common pitfalls and learn how to avoid them. Happy coding!

Section 7: Building a Simple To-Do List Project

Alright, it’s time to put all that theory into practice. We’re going to build a simple project that demonstrates all the concepts we’ve covered in this article. We’ll create a dynamic, interactive to-do list where users can add tasks, mark them as completed, and remove them. Let’s get started!

Step 1: Setting Up the HTML

First, let’s set up the basic structure of our to-do list in HTML. We’ll need an input field for adding new tasks, a button for submitting the input, and an unordered list for displaying the tasks.




    To-Do List


    
    
    

    Step 2: Adding Tasks

    Next, let’s use JavaScript to add tasks to the list. We’ll select the input field and the button, and set up an event listener on the button that adds a new list item to the task list whenever the button is clicked.

    let taskInput = document.querySelector('#taskInput');
    let addTaskButton = document.querySelector('#addTaskButton');
    let taskList = document.querySelector('#taskList');
    
    addTaskButton.addEventListener('click', function() {
        let task = taskInput.value; // get the input value (the new task)
        let listItem = document.createElement('li'); // create a new list item
        listItem.textContent = task; // set the text content of the list item
        taskList.appendChild(listItem); // append the list item to the task list
        taskInput.value = ''; // clear the input field
    });
    

    Step 3: Marking Tasks as Completed

    Now, let’s add the ability to mark tasks as completed by clicking on them. We’ll set up an event listener on the task list that checks if the target of a click event is a list item, and if so, toggles the ‘completed’ class on it.

    taskList.addEventListener('click', function(event) {
        if (event.target.tagName === 'LI') {
            event.target.classList.toggle('completed');
        }
    });
    

    Step 4: Removing Tasks

    Finally, let’s allow users to remove tasks from the list. We’ll add a ‘Remove’ button to each task, and set up an event listener on the task list that removes a task when its ‘Remove’ button is clicked.

    addTaskButton.addEventListener('click', function() {
        // ...previous code...
    
        let removeButton = document.createElement('button');
        removeButton.textContent = 'Remove';
        listItem.appendChild(removeButton);
    });
    
    taskList.addEventListener('click', function(event) {
        if (event.target.tagName === 'BUTTON') {
            let task = event.target.parentElement;
            taskList.removeChild(task);
        }
    });
    

    Step 5: Add Some Style

    body {
        font-family: Arial, sans-serif;
        padding: 20px;
    }
    #taskInput, #addTaskButton {
        margin: 10px 0;
    }
    #taskList {
        list-style-type: none;
        padding: 0;
    }
    #taskList li {
        background-color: #f9f9f9;
        border: 1px solid #ddd;
        margin-bottom: 10px;
        padding: 10px 20px;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }
    #taskList li.completed {
        text-decoration: line-through;
    }
    button {
        background-color: #ff6347;
        color: white;
        border: none;
        padding: 5px 10px;
        cursor: pointer;
    }
    button:hover {
        background-color: #ee3120;
    }
    

    And there you have it! You’ve built a dynamic, interactive to-do list using the DOM manipulation techniques we’ve covered in this article. This is just a simple example, but the possibilities are endless. Keep practicing, keep experimenting, and most importantly, keep having fun! Happy coding!

    P.S. If you have problems with your code, remember to check on the following:

    1. HTML Structure: Make sure your HTML structure matches the one used in the code. The IDs of the elements (taskInput, addTaskButton, taskList) should match exactly.
    2. JavaScript Placement: If your JavaScript code is in a