# Day 2 Overview: The DOM

## Course Project Overview: What will I be building?

### App: Coffee Masters

* Web app for a coffee shop
    
* Menu of products
    
* Details of each product
    
* Order with Cart
    
* Data in JSON
    
* No JavaScript written
    

To start, I always thought that the DOM and the HTML file in my code editor that was served to the browser were the same thing. I mean, when I opened my console to inspect objects I saw pretty much the same HTML file I saw in my editor. However, I was wrong, since there is a difference between the DOM and the HTML file that gets loaded. The HTML file is the string representation of the DOM, but the DOM is always a structure in memory. The head and body can be implicit in an HTML file, which will then be added in the DOM, because it’s mandatory in the DOM. The browser parses our HTML code and creates the DOM from it, so they’re not the same.

The only thing mandatory in an HTML file is the `<!DOCTYPE html>` and `<title>` tags, and even without them, it still might work on some browsers apparently, lol.

```html
<!DOCTYPE html>
<style>
	body { background: red;}
</style>
<title>My first HTML test</title>

<h1>Quick HTML code</h1>
```

When the browser begins parsing our HTML file, it begins creating the `<body>` tag in the DOM when it encounters my first visible element, something like an `<h1>` tag:

```html
<!DOCTYPE html>
<title>Title</title>
<script></script>

<h1>Visible Text</h1>
```

## Scoping querySelector

While we can use the DOM API anywhere and everywhere, we can also scope its usage to the actual HTML element I'm interested in. For example, I could look for my `<span>` element within my `<nav>` element using the DOM API:

```javascript
document.querySelector('span');

-> <span id='badge' hidden></span>
```

But we can scope it to just the element since each HTML element also has access to the DOM API. Since I'm now using a variable, this allows me to query only within the nav, which allows me to “cache” the nav object and query it many times, which makes it more performant.

```javascript
let nav = document.querySelector('nav');
nav.querySelector('span');

-> <span id='badge' hidden></span>
```

## Adding Scripts `async` & `defer`

When the browser is parsing the HTML line by line, and it encounters a `<script>` tag, it will stop parsing the rest of the HTML file, download the `js` file in the script's `src`, and execute the file. When it’s done, it will continue with the rest. This can lead to slow page loads if the JS file being executed is big enough. The now deprecated solution to this, which I learned back at Hack Reactor, was to simply put the `<script>` tag at the bottom of the `<body>` tag so that it would finish rendering the HTML first, and then the JS file. However, we now have some attributes that can be applied such as `defer` or `async` which defers the script download and execution.

If you don’t know which one to use, just use `defer`. It’s a boolean value so no need to give it any argument. It will do the following:

* When the browser finds the script, it will download the JS file, but will not halt the parsing of the HTML, it will do it in parallel
    
* When the browser finishes parsing the HTML, it will then execute the JS file. So it will defer the execution, not the downloading of the file.
    
* **When to use async:** more suitable for small scripts that really need to be executed as soon as possible such as analytics, pings to server, etc. It will not halt parsing, but will download the file, and instead of waiting for the HTML to finish parsing, when the JS file is finished downloading it will halt HTML parsing and execute the file.
    

## Main Script Setup

Most of the time what we want to do is work with the page. Since I'm now using `defer` and the JS file will be executed once the HTML is finished parsing, I can immediately do things like `document.getElementById()`, etc.

However, this isn't a good practice because some browsers in theory might still be working on the creation of the DOM in memory. This is why the `window` object has an event that we can listen to that specifies when the DOM is ready for manipulation: `window.addEventListener('DOMContentLoaded');`

```jsx
// it's better to wait for the event for manipulation since it happens
// before rendering
window.addEventListener('DOMContentLoaded', () => {
	let nav = document.querySelector('nav');
	console.log(nav);
);
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">There is also a <code>load</code> event, which waits for everything to be loaded, such as images, videos, assets, and everything. If we wait for this, we're missing the opportunity to manipulate the DOM earlier.</div>
</div>

## Event Binding & Handlers

### Each DOM element has a list of possible events we can listen to:

* Basic: `load`, `click`, `dblclick`
    
* Value: `change`
    
* Keyboard Events: `keyup`, `keydown`, `keypress`
    
* Mouse Events: `mouseover`, `mouseout`, etc
    
* Pointer and Touch Events
    
* Scroll, Focus, and more APIs
    

Some specific objects have special events:

* `DOMContentLoaded`, `popstate` in `window`
    

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">The spec’s naming pattern is to use lowercase with no word separator for event names. That’s why we can end up with names like <code>webkitcurrentplaybacktargetiswirelesschanged</code></div>
</div>

### Binding functions to events in DOM objects

* `onevent` (more classic): one property for every event `onload` `onclick`, key here is that everything is lowercase, in React camelCase.
    
* `addEventListener`
    

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">When using <code>oneventname</code> technique, only one function can be attached per event/object combination. Since it’s a property (setter, getter) it will be overwritten.</div>
</div>

When using `addEventListener()` we can attach more than one event handler, since it uses the **Observer Design Pattern** aka **Publish/Subscribe**, so that we can subscribe to multiple events and fire all of them.

```javascript
function eventHandler(event) {
    //do something
}

element.onload = eventHandler;
element.onload = (event) => {
	//replaces the first eventHandle
}

element.addEventListener('click', eventHandler);
element.addEventListener('load', eventHandler);
element.addEventListener('load', (event) => {
	//do something else
});
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This allows us to separate our concerns, knowing that all of them will fire, no matter how many times we’ve called it.</div>
</div>

## Advanced Event Handling

```javascript
function eventHandler(event){
	//do something
};

const options = {
	once: true,
	passive: true
};

element.addEventListener('load', eventHandler, options);
element.removeEventListener('load', eventHandler);
```

In the example of someone scrolling through a site, by default, the browser will wait for the event handler to see if we're changing the DOM when we set `passive: true`. In this example, I'm telling the browser to safely do what it’s doing and that I won't be changing the DOM; meaning I don’t have to wait for it to finish.

Removing event listeners is only helpful when doing a SPA and adding and removing elements on the page. We don’t need to remove the event listener for `DOMContentLoaded` because when a user is leaving or closing the browser, we don’t need to clean up JS, it will happen automatically. To be completely honest, I don't think I fully captured what the point of this was, but I don't anticipate having to implement it anytime soon-- and if I have to I'll be sure to ask questions of more senior engineers.

### Dispatching Custom Events

I can also reuse the same system I've been using with adding event listeners with my own custom events and messages:

```jsx
const event = new Event('mycustomevent');
element.dispatchEvent(event);
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">We can also broadcast events throughout the DOM. This is kind of a Context, like in React. Everyone in the DOM can subscribe via a Provider.</div>
</div>

## Helpful Shorthand Methods

One of the biggest developer fears is that vanilla JS is too verbose, however, JS is a very flexible language. The following code is one example of how we can abstract away some of the verbose-ness:

```javascript
const $ = () => document.querySelector.call(this, arguments);
const $$ = () => document.querySelectorAll.call(this, arguments);
HTMLElement.prototype.on = (a,b, c) => this.addEventListener(a, b, c);
HTMLElement.prototype.off = (a, b) => this.removeEventListener(a, b);
HTMLElement.prototype.$ = (s) => this.querySelector(s);
HTMLElement.prototype.$ = (s) => this.querSelectorAll(s);
```

## Fetching Data

### Creating Initial Services

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">What’s a service? In JS: nothing. Just a concept, a design pattern that we are defining. Can have any name, nothing exists in the DOM called a “service”. It is an object or way to offer different services to the app, such as fetching data from a network and/or a Store that stores data that is global to the app aka the state of the app.</div>
</div>

```javascript
//service/API.js
const API = {
	url: '/data/menu.json',
	fetchMenu: async () => {
		const result = await fetch(API.url);
		return await result.json();
	}
}

//services/Store.js
import API from './API.js';

const Store = {
	menu: null,
	cart: []
}

//app.js
import Store from './services/Store.js';
import API from './services/API.js';
```

An ECMAScript Module means that we don’t want our variables to be global, so we can export our functions from our files to be used throughout our app.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Before we can being importing our functions from our other modules, we can’t simply go and <code>import</code> in our <code>app.js</code> file, we need to go into our HTML <code>&lt;script&gt;</code> tag and add the <code>type</code> attribute and set it to <code>"module"</code> or else we get the following error:</div>
</div>

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690568906619/303b4bee-a364-40b1-9c18-63e588133dfc.png align="center")

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">In the browser, without something like Babel, we need to include file extensions for our functions to work. IE: if I’m importing <code>API</code> from <code>./API</code> I need to add the <code>.js</code> or else it won’t work.</div>
</div>

## Loading Menu Data

In JS, if we don’t use modules, then everything is global, which can lead to conflicts between several variable names.

Now that we’ve set our type to module, we can import our functions just like I’m used to in something like React.

However, for our purposes, `Store` needs to be a global store, but it’s a module, so how can we make this change? We can use one pattern which breaks the module pattern by using the `window` object:

```javascript
//app.js
window.app = {};
app.store = Store;
```

Now, every time I access `app.store` I'm effectively "hooking" into a global object available everywhere in my app.

So let’s start fetching data: We can include our `fetchMenu()` function inside of our event listener:

```javascript
window.addEventListener('DOMContentLoaded', async() => {
    const menu = await API.fetchMenu();
})
```

However, we can do better by also adding another service that only handles working with my data model because it will increase the readability of my code.

```javascript
//services/API.js
const API = {
  url: '/data/menu.json',
  fetchMenu: async () => {
    const result = await fetch(API.url);
    return await result.json();
  },
};

export default API;
```

```jsx
//services/Store.js
const Store = {
    menu: null,
    cart: []
};

export default Store;
```

```jsx
//services/Menu.js
import API from './API.js';

export async function loadData() {
  app.store.menu = await API.fetchMenu();
}
```

```jsx
//app.js
import API from './services/API.js';
import Store from './services/Store.js';
import { loadData } from './services/Menu.js';

window.app = {};
app.store = Store;

window.addEventListener('DOMContentLoaded', async () => {
  loadData();
});
```

We now have data!!! But it's in memory. The next part will be how to render our data to our screen and then react to changes in our data-- stay tuned!
