I already found JavaScript, but it was such a good learning experience that I wanted to do a rerun of Chris Ferdinandi’s Vanilla JS Academy for the class of October 2021. Then both ✨ new job ✨ and life in general happened, and I never got around to completing. But this is it.

At work, we currently have a week of “flexible work” that can be used for learning. My goal is to build all the academy projects — and publish daily notes to keep myself accountable. (Direct quotes are from either MDN or the Vanilla JS Academy course material.)


Grab elements from the DOM

  • Pass any valid CSS selector into either…
  • document.querySelector() to get the first element in the DOM
  • document.querySelectorAll() to get multiple elements

Get & set element properties 🔨

I have the HTML elements. To actually do stuff with them in my scripts, I can access their properties. They have a whole range! Some read only, others can both get and set values. Examples:

  • Element.classList will read a list of class attributes
  • Element.className can read but also set a new CSS class to an element
  • Element.id to get or set a value as an ID
  • Element.innerHTML to get or set markup within the element
  • Node.parentElement to read a DOM node’s parent element

I’m still somewhat confused by when something relates to the Element vs Node. I understand that they are different interfaces in the Web APIs. Perhaps that is all I need to know at the moment? And that when looking for properties and methods on MDN, I may want to check multiple lists:

The DOM Node interface is an abstract base class upon which many other DOM API objects are based, thus letting those object types to be used similarly and often interchangeably. As an abstract class, there is no such thing as a plain Node object. All objects that implement Node functionality are based on one of its subclasses. Most notable are Document, Element, and DocumentFragment.

Hm, okay? I’m sure this will make more sense to me later.

Listen for events 🎧

The world of events are a bit of a mind melt to approach, trying to get an overview or a mental model of it all. But getting familiar with the humble click event in basic projects is a good start.

let btn = document.querySelector("#click-me");

btn.addEventListener("click", function (event) {
  console.log(event); // The event details
  console.log(event.target); // The clicked element
});

Run the EventTarget.addEventListener() method on the element you want to listen for events on. It accepts two arguments: the event to listen for, and a callback function to run when the event happens. You can pass the event into the callback function as an argument. The event.target property is the element that triggered the event.

Loop over elements ♻️

  • for…of to define a variable but no index
  • Array.forEach() to iterate over arrays with access to index
  • NodeList.forEach() same but for list of nodes

The forEach() methods really are for each, I can't break the loop.

Check if an element matches a selector 👯

Element.matches() will tell me if the element matches the selector I pass into the method.

Delegate event listening 👔

Because I can only add event listeners to individual elements, not to a node list. It’s possible to loop though elements, for example all the buttons on a page. But event delegation is generally better for performance.

  • Attatch listener to a parent element, like document
  • Events on elements inside will bubble up
  • …and then use event.target to know exactly what was clicked
document.addEventListener("click", function (event) {
  if (event.target.matches(".click-me")) {
    // do stuff
  }
});

Work with data attributes 💙

<div
  id="evening-plans"
  data-obligations="something that can wait for tomorrow"
  data-movie="Star Wars"
  data-drink="beer"
></div>
const el = document.querySelector("#evening-plans");

// Get and remove attributes
console.log("Watching: ", el.getAttribute("data-movie"));
el.removeAttribute("data-obligations");

// Set a different drink value
el.setAttribute("data-drink", "wine");

// Has we got snacks?! No?!? Then add popcorn
if (!el.hasAttribute("data-snack")) {
  el.setAttribute("data-snack", "popcorn");
}

// The evening plans element now has these data attributes:
// data-movie="Star Wars" data-drink="wine" data-snack="popcorn"

These four methods can also be used to get, set, remove, and check for other types of attributes that I may want for my elements (not just data attributes). Examples from the Toggle Password project in the course:

  • Use element IDs in a data attribute: data-toggle="#current-password, #new-password"
  • and then get the attribute value with getAttribute("data-toggle")
  • Also event delegation with if (!event.target.matches("[data-toggle]")) return;

Grab text and change text 📝

Count words

For the Word Count project in the course, I have text from a textarea. A neat way to count the words, is to first turn this string into an array, and then access that array’s length property.

  • String.split() method to return an array of substrings, split on a delimiter
  • Array.prototype.length property to return the number of elements in this array

Filter an array

create a new array with only elements that pass a test you include as a callback function. The callback accepts three arguments: the current item in the loop’s value, its index, and the array itself. All three are optional.

let numbers = [2, 7, 8, 11, 20, 113];

// Create new array with only numbers above 10
// This array method will loop through each item under the hood
let biggerThanTen = numbers.filter(function (item) {
  // The test to pass to be included in the new array
  return item > 10; // True or false?
});

MDN has syntax examples, and I found it helpful to see these 3 variants next to each other:

// Arrow function
filter((element) => { /* ... */ });

// Callback function
filter(callbackFn);

// Inline callback function
filter(function (element) {
  /* ... */
});

Great first day of javascripting recap. Tomorrow we Promise and fetch() from APIs.