Using alerts and prompts is really fun, but javascript is way more powerful than just alerts and prompts! Most every site that you encounter uses a lot of javascript, and that javascript is used to manipulate the DOM.
DOM stands for "Document Object Model", which is more or less just a super fancy name for a bunch of javascript variables and methods that interact with our HTML and CSS. By using this javascript & html/css bridge, we can easily interact with the HTML by using javascript, which lets us change colors, text sizes, validate forms, etc.
The web browser (e.g. Firefox, Chrome, etc.) turns every html tag into a javascript object! Let's take a very basic website:
1
2<html>
3 <head>
4 <title> I am a website </title>
5 </head>
6 <body>
7 <p>
8 Hello World
9 </p>
10 <div>
11 Isn't web programming really cool?
12 </div>
13 </body>
14</html>
What happens behind the scenes is that our browsers actually create a "model" of our site's elements. Each HTML element gets modelled as a javascript object, and each element inside of our elements has a smaller object! So, if we start at doctype html (our document) and inside of that object we have a head and a body. Inside of the head we have a title, and inside of our body we have a paragraph element and a div element. Each of those in turn have text inside them!
Now, looking at diagrams is fun, but let's see an actual document. Let's look at how the html above works. Click here, and then open your developer console (in chrome it's under developer, in firefox it's under window). In your console, type: console.dir(document)
.
console.dir()
is a way for us to click through javascript objects in our developer console. Now, the document we see here is really big! That's because there's a lot going on behind the scenes other than just a few elements.
In your document click on body
. We can see that body has a lot of elements inside of it. If you click then on childNodes
you can see the children of <body>
:
xxxxxxxxxx
61childNodes: NodeList (5)
20 #text " "
31 <p> Hello World </p>
42 #text " "
53 <div> Isn't web programming really cool? </div>
64 #text " "
This is the document object model in a nutshell! This is what lets us access parts of our web page with javascript!
Let's explore just a little more. Let's take our earlier example, and look at what nested elements look like:
xxxxxxxxxx
171
2<html>
3 <head>
4 <title> I am a website </title>
5 </head>
6 <body>
7 <p>
8 Hello World
9 </p>
10 <div>
11 <p>
12 You could go visit google if you want by clicking below!
13 </p>
14 <a href='www.google.com'> Go to google! </a>
15 </div>
16 </body>
17</html>
Now let's take a look. If you go to the console and write console.dir(document)
, then open up body
and click on childNodes
, you'll see that one of our children ALSO has child nodes!
xxxxxxxxxx
91childNodes: NodeList (5)
20 #text " "
31 <p> Hello World </p>
42 #text " "
53 <div>
6<p> You could go visit google if you want by clicking below! </p>
7<a href="www.google.com"> Go to google! </a>
8</div>
94 #text " "
There's a lot to the DOM that we'll not cover (and you'll probably never cover - there's so much to the DOM)! It's ok not to know everything. That's what google is for!
So now that we know about what the DOM is and how it works (or at least have a general understanding of a little bit), let's look at how to work with it!
Let's take a look back at our original (very complex) page. Open the page and go to your developer console. In your console type:
xxxxxxxxxx
11var myLink = document.querySelector('a');
Now, type myLink
in your console. What does it return? You should see:
xxxxxxxxxx
11<a href="www.google.com"> Go to google! </a>
What we can then do, is use the DOM to manipulate what's being displayed! Try typing:
xxxxxxxxxx
11myLink.style.fontSize = '500%'
Your link should've gotten a whole lot bigger!
That's not all either! We can use functions to manipulate our doms as well! Go back to our page, and this time, in your console, type:
x1// just to set our link back to its original
2myLink.style.fontSize = '100%'
3var size = 10
4
5setInterval( function() {
6 myLink.style.fontSize = size + 'px'
7 size = size + 1
8}, 50)
You might want to refresh your page (or else the link will just keep growing)!
That function we used for setInterval may just look like fun and games, but what that shows us is that we can tie javascript functions directly to our DOM, which means, we can tie buttons (and so much more!) to our DOM!
There are a lot of DOM selectors. You can ultimately select anything in the document by looking at what's inside of the document (you can view with console.dir(document)
). Try that again on our basic web page above.
Now if you go to your console and type:
xxxxxxxxxx
11var myURL = document.URL
You'll find that myURL has a URL inside of it! Everything we'll be working with lives inside the document! We'll use document.SOMETHING
for everything!
We've already looked at document.querySelector()
, but there are some other document methods we'll dive into as well:
document.getElementById()
: for when you want to get one specific element.document.getElementsByClassName()
: for when you want to get all elements of a particular class.document.getElementsByTagName()
: for when you want to get all elements of a certain tag (e.g. all <p>
elements, or all <h3>
elements). document.querySelector()
: for when you want to search by a css style'd query and grab the very first element. document.querySelectorAll()
: for when you want to search by a css style'd query and grab all the elements in the DOM.
getElementById is pretty self explanatory. It grabs a specific element by its ID. If you recall, back when we were coding our sites and learning CSS, we saw that you could technically style a webpage using multiple of the same IDs. An ID is supposed to be a unique thing. Let's see why:
xxxxxxxxxx
341
2<html>
3 <head>
4 <title> I am a website </title>
5 <style>
6 #greyDiv {
7 background-color: lightgrey;
8 }
9
10 .coolClass {
11 font-size: 2em;
12 font-weight:bold;
13 }
14 </style>
15 </head>
16 <body>
17 <p class='coolClass'>
18 Hello World
19 </p>
20 <div id='greyDiv'>
21 <p>
22 You could go visit google if you want by clicking below!
23 </p>
24 <a href='www.google.com'> Go to google! </a>
25 </div>
26 <p class='coolClass'>
27 I'm just a boring paragraph.
28 </p>
29 <div id='greyDiv'>
30 I like to steal IDs!
31 </div>
32
33 </body>
34</html>
See how both <div>
elements have the id "greyDiv
"? Styling wise, our browser allows for multiple of the same IDs. Now, let's try selecting our IDs with document.getElementById()
. Open the browser's console and type:
xxxxxxxxxx
11var myDiv = document.getElementById('greyDiv')
Because IDs are supposed to be unique, the document's function getElementById()
only grabs the element with the first ID it recognizes. Notice, though, that it not only grabs the <div>
but also everything inside of it. That's because the elements inside of the <div>
are child nodes
of the <div>
itself. So when we select a specific DOM element, we're not only grabbing the element itself, we're also grabbing all of its child elements!
Reminder: When you type myDiv
into the console, notice how it gives you a bunch of HTML. Type console.dir(myDiv)
to see the object itself.
Suppose that you didn't want to only grab a specific element, but wanted every single element using a specific class (say you wanted to change some class styling), you can grab elements by their class names!
Go into our page, and type:
xxxxxxxxxx
11var classElements = document.getElementsByClassName('coolClass')
Up to now, we've only seen individual elements returned (with some nested elements inside). Now, we actually return an "HTML Collection" which is a fancy way of saying that classElements
is kind of like an array of html elements that use coolClass
as a class.
Sometimes you need to change specific types of elements on your page (say you want to change your list elements from all bullets to circles, because why not?), then you'd use getElementsByTagName()
. Take a look at our boring list below:
xxxxxxxxxx
171
2<html>
3 <head>
4 <title> I am a website </title>
5 </head>
6 <body>
7 <div>
8 I am a boring site.
9 </div>
10 <ul>
11 <li>Boring List</li>
12 <li>Boring List 2 </li>
13 <li>Boring List 3 </li>
14 <li>Boring List 4 </li>
15 </ul>
16 </body>
17</html>
What if we wanted to spice our list up? Remember when we turned our list bullets into cats? Let's do that, but with javascript:
First, select all of the list items <li>
s:
xxxxxxxxxx
11var myList = document.getElementsByTagName('li')
Now, let's take our cat style and store it in a variable!
xxxxxxxxxx
51myStyle = `background-image: url('https://media.giphy.com/media/V0YMxvqOXOkEw/giphy.gif'); background-repeat: no-repeat;
2 list-style-type: none;
3 padding-left:75px;
4 padding-bottom:50px;
5`
Note: Above we used the tick ` (to the left of the 1) to lets us create multi-line strings!.
Now that we have a special style, let's create a loop in the console to loop over all of our list elements and add our new style!
xxxxxxxxxx
31for(var i = 0; i < myList.length; i++) {
2 myList[i].style = myStyle
3}
BAM! Now we've made our list significantly better with cats.
Query selector is a method that basically does what we've done above, but ignores whether or not we're looking for an ID or a given class or a tag. Query selector returns the first element that matches what query it's given. So let's take our site from earlier with all of the ids and classes:
xxxxxxxxxx
341
2<html>
3 <head>
4 <title> I am a website </title>
5 <style>
6 #greyDiv {
7 background-color: lightgrey;
8 }
9
10 .coolClass {
11 font-size: 2em;
12 font-weight:bold;
13 }
14 </style>
15 </head>
16 <body>
17 <p class='coolClass'>
18 Hello World
19 </p>
20 <div id='greyDiv'>
21 <p>
22 You could go visit google if you want by clicking below!
23 </p>
24 <a href='www.google.com'> Go to google! </a>
25 </div>
26 <p class='coolClass'>
27 I'm just a boring paragraph.
28 </p>
29 <div id='greyDiv'>
30 I like to steal IDs!
31 </div>
32
33 </body>
34</html>
Query selector uses the same types of notation as CSS, so if you want to select an id (such as greyDiv
), you'd have to use the css syntax: #greyDiv
, and similarly, if you wanted to select a class, you'd have ot use the syntax .coolClass
.
Now to select an ID with query selector we can write:
xxxxxxxxxx
11var firstClass = document.querySelector('.coolClass')
Did you notice that the only element inside of firstClass
is:
xxxxxxxxxx
31<p class="coolClass">
2 Hello World
3</p>
This is because query selector only selects the first item it comes across.
As a quick note, when you change the style of a selected ID or a class, you're not changing the ID or the Class styling itself, you're only changing the elements that you've selected.
Try writing:
xxxxxxxxxx
11firstClass.style = 'background-color:red'
If you look inside firstClass again, now it is:
xxxxxxxxxx
31<p class="coolClass" style="background-color: red;">
2 Hello World
3</p>
It still is inheriting its colors from from coolClass
, but the styling on the element itself is what changed.
Our Query selector only selects a single item, but if we want to get all items of a specific type, we can use document.querySelectorAll()
. This grabs not just the first item, but all items that match the query! Let's try what we did above, again!
On the page above, go to your console, and type:
xxxxxxxxxx
11var allClasses = document.querySelectorAll('.coolClass')
This will select not just the first class like above, but all the elements that use coolClass
:
xxxxxxxxxx
31NodeList (2) = $1
20 <p class="coolClass"> Hello World </p>
31 <p class="coolClass"> I'm just a boring paragraph. </p>
Now, just like above if we write a quick for loop:
xxxxxxxxxx
31for(var i = 0; i < allClasses.length; i++ ){
2 allClasses[i].style = 'background-color:red'
3}
Now we've turned all of our cool classes red!
We've already worked with a number of styling methods, however, we've only really accessed the styling in a specific way, like above where we wrote:
xxxxxxxxxx
11allClasses[i].style = 'background-color:red'
Our initial choice of styling in the previous examples was entirely for familiarity. We could just as easily have written:
xxxxxxxxxx
11allClasses[i].style.background = 'red'
The DOM lets us access styles with the javascript dot operator. While we may go back and forth in our styling, it's good to note that you can access not only the 'style' attribute, but also specific types of stylings based entirely off of the DOM's dot operators!
So far we've only worried about colration with our styling. Any styling that we've done with CSS, we can also do here:
xxxxxxxxxx
171
2<html>
3 <head>
4 <title> I am a website </title>
5 </head>
6 <body>
7 <div>
8 I am a boring site.
9 </div>
10 <ul>
11 <li>Boring List</li>
12 <li>Boring List 2 </li>
13 <li>Boring List 3 </li>
14 <li>Boring List 4 </li>
15 </ul>
16 </body>
17</html>
Let's wrap our list in a border. First we need to select the list:
xxxxxxxxxx
11var myList = document.querySelector('ul')
Now let's add a border:
xxxxxxxxxx
11myList.style.border = '1px solid blue'
So far we've styled entirely by adding single styles to a given class, ID, or element, but what if we wanted to give multiple styles? We could do what we did before an add one giant string of styles to our elements. That can be time consuming.
Above, when we changed our background bullets to cats, we used this simple for loop with a style string:
xxxxxxxxxx
81myStyle = `background-image: url('https://media.giphy.com/media/V0YMxvqOXOkEw/giphy.gif'); background-repeat: no-repeat;
2 list-style-type: none;
3 padding-left:75px;
4 padding-bottom:50px;
5`
6for(var i = 0; i < myList.length; i++) {
7 myList[i].style = myStyle
8}
Without the for loop that whole style sting and loop would look like:
xxxxxxxxxx
201myList[0].style.backgroundImage = "url('https://media.giphy.com/media/V0YMxvqOXOkEw/giphy.gif')"
2myList[0].style.backgroundRepeat = 'no-repeat'
3myList[0].style.listStyleType = 'none'
4myList[0].style.paddingLeft = '75px'
5myList[0].style.paddingBottom = '50px'
6myList[1].style.backgroundImage = "url('https://media.giphy.com/media/V0YMxvqOXOkEw/giphy.gif')"
7myList[1].style.backgroundRepeat = 'no-repeat'
8myList[1].style.listStyleType = 'none'
9myList[1].style.paddingLeft = '75px'
10myList[1].style.paddingBottom = '50px'
11myList[2].style.backgroundImage = "url('https://media.giphy.com/media/V0YMxvqOXOkEw/giphy.gif')"
12myList[2].style.backgroundRepeat = 'no-repeat'
13myList[2].style.listStyleType = 'none'
14myList[2].style.paddingLeft = '75px'
15myList[2].style.paddingBottom = '50px'
16myList[3].style.backgroundImage = "url('https://media.giphy.com/media/V0YMxvqOXOkEw/giphy.gif')"
17myList[3].style.backgroundRepeat = 'no-repeat'
18myList[3].style.listStyleType = 'none'
19myList[3].style.paddingLeft = '75px'
20myList[3].style.paddingBottom = '50px'
While both options work, we don't have to waste our time with either option! They're both significantly more time consuming than createing a brand new class.
Let's assume we already had a cat-class defined in our code:
xxxxxxxxxx
51.cat-class {background-image: url('https://media.giphy.com/media/V0YMxvqOXOkEw/giphy.gif'); background-repeat: no-repeat;
2 list-style-type: none;
3 padding-left:75px;
4 padding-bottom:50px;
5}
Now, when we want to change our bullet points, we no longer have to do all of this extra work! All we need to do is add a class to our elements:
xxxxxxxxxx
11 myList.classList.add('cat-class')
Now when we go to update our styles we can just:
xxxxxxxxxx
31for(var i = 0; i < myList.length; i++) {
2 myList[i].classList.add('cat-class')
3}
Problem solved!
Take the list items on our "boring list" site, and select items and try updating them. You can update by color, font (size, family, etc.), opacity, style, etc. The goal of this is to get used to using the DOM to manipulate our sites!
What makes websites reactive is that there are special things called events
. Each event is something that happens on the website like a mouse moving over a portion of your site or clicking on a button! A site reacts to these events by using event handlers.
Event handlers are javascript functions that you can attach to specific elements that handle specific user interactions! Let's take a look at a basic list from our very first lecture:
HTML:
xxxxxxxxxx
1
2<html>
3 <head>
4 </head>
5 <body>
6 <h1> Welcome to my site! </h1>
7 <hr />
8 <ul type='square'>
9 <li>I really like to write code</li>
10 <li>Does that make me a square?</li>
11 <li>Some people do call me a block head...</li>
12 <li>Maybe they're just not seeing me at the right ANGLE?</li>
13 </ul>
14 </body>
15</html>
Now let's add some CSS to our site:
x
1 .done {
2 text-decoration: line-through;
3 opacity: 0.5;
4 }
5
6 .selected {
7 color: green;
8 }
Notice how nothing happened! That's because we haven't implemented any of our css classes! We don't want to hard code our classes into our site! We want to attach them to the DOM's event listeners!
What we'll want to do is grab every single list item <li>
and then attach an event listener to each. Let's grab an event:
xxxxxxxxxx
11var lis = document.querySelectorAll("li")
Now we've selected all of our <li>
s. We'll want to add an event listener to each. But what event listeners? We want to have a mouseover
, a mouseout
, and a click
. Let's try adding those event listeners to each <li>
with a for loop:
x
1for(var i = 0; i < lis.length; i++){
2 lis[i].addEventListener("mouseover", function(){
3 this.classList.add("selected");
4 });
5
6 lis[i].addEventListener("mouseout", function(){
7 this.classList.remove("selected");
8 });
9
10 lis[i].addEventListener("click", function(){
11 this.classList.toggle("done");
12 });
13}
14
Now, let's see what those all look like together!
You may wonder why we should bother using event handlers if they're just going to put lines through list items, change colors of pages, change font sizes, but using event handlers can be an incredibly powerful tool! Let's spend the rest of today talking about making a game!
xxxxxxxxxx
311
2<html>
3<head>
4 <title>Color Game</title>
5
6<body>
7<h1>
8 The Great
9 <br>
10 <span id="colorDisplay">RGB</span>
11 <br>
12 Color Game
13</h1>
14
15<div id="stripe">
16 <button id="reset">New Colors</button>
17 <span id="message"></span>
18 <button class="mode">Easy</button>
19 <button class="mode selected">Hard</button>
20</div>
21
22 <div id="container">
23 <div class="square"></div>
24 <div class="square"></div>
25 <div class="square"></div>
26 <div class="square"></div>
27 <div class="square"></div>
28 <div class="square"></div>
29 </div>
30</body>
31</html>
CSS:
xxxxxxxxxx
751body {
2 background-color: #232323;
3 margin: 0;
4 font-family: "Montserrat", "Avenir";
5}
6
7.square {
8 width: 30%;
9 background: purple;
10 padding-bottom: 30%;
11 float: left;
12 margin: 1.66%;
13 border-radius: 15%;
14 transition: background 0.6s;
15 transition: background 0.6s;
16 transition: background 0.6s;
17}
18
19#container {
20 margin: 20px auto;
21 max-width: 600px;
22}
23
24h1 {
25 text-align: center;
26 line-height: 1.1;
27 font-weight: normal;
28 color: white;
29 background: steelblue;
30 margin: 0;
31 text-transform: uppercase;
32 padding: 20px 0;
33}
34
35#colorDisplay {
36 font-size: 200%;
37}
38
39#message {
40 display: inline-block;
41 width: 20%;
42}
43
44#stripe {
45 background: white;
46 height: 30px;
47 text-align: center;
48 color: black;
49}
50
51.selected {
52 color: white;
53 background: steelblue;
54}
55
56button {
57 border: none;
58 background: none;
59 text-transform: uppercase;
60 height: 100%;
61 font-weight: 700;
62 color: steelblue;
63 letter-spacing: 1px;
64 font-size: inherit;
65 transition: all 0.3s;
66 transition: all 0.3s;
67 transition: all 0.3s;
68 outline: none;
69}
70
71button:hover {
72 color: white;
73 background: steelblue;
74}
75
Javascript:
xxxxxxxxxx
1131var numSquares = 6;
2var colors = [];
3var pickedColor;
4var squares = document.querySelectorAll(".square");
5var colorDisplay = document.getElementById("colorDisplay");
6var messageDisplay = document.querySelector("#message");
7var h1 = document.querySelector("h1");
8var resetButton = document.querySelector("#reset");
9var modeButtons = document.querySelectorAll(".mode");
10
11
12init();
13
14function init(){
15 setupModeButtons();
16 setupSquares();
17 reset();
18}
19
20function setupModeButtons(){
21 for(var i = 0; i < modeButtons.length; i++){
22 modeButtons[i].addEventListener("click", function(){
23 modeButtons[0].classList.remove("selected");
24 modeButtons[1].classList.remove("selected");
25 this.classList.add("selected");
26 this.textContent === "Easy" ? numSquares = 3: numSquares = 6;
27 reset();
28 });
29 }
30}
31
32function setupSquares(){
33 for(var i = 0; i < squares.length; i++){
34 //add click listeners to squares
35 squares[i].addEventListener("click", function(){
36 //grab color of clicked square
37 var clickedColor = this.style.background;
38 //compare color to pickedColor
39 if(clickedColor === pickedColor){
40 messageDisplay.textContent = "Correct!";
41 resetButton.textContent = "Play Again?"
42 changeColors(clickedColor);
43 h1.style.background = clickedColor;
44 } else {
45 this.style.background = "#232323";
46 messageDisplay.textContent = "Try Again"
47 }
48 });
49 }
50}
51
52
53function reset(){
54 colors = generateRandomColors(numSquares);
55 //pick a new random color from array
56 pickedColor = pickColor();
57 //change colorDisplay to match picked Color
58 colorDisplay.textContent = pickedColor;
59 resetButton.textContent = "New Colors"
60 messageDisplay.textContent = "";
61 //change colors of squares
62 for(var i = 0; i < squares.length; i++){
63 if(colors[i]){
64 squares[i].style.display = "block"
65 squares[i].style.background = colors[i];
66 } else {
67 squares[i].style.display = "none";
68 }
69 }
70 h1.style.background = "steelblue";
71}
72
73resetButton.addEventListener("click", function(){
74 reset();
75})
76
77function changeColors(color){
78 //loop through all squares
79 for(var i = 0; i < squares.length; i++){
80 //change each color to match given color
81 squares[i].style.background = color;
82 }
83}
84
85function pickColor(){
86 var random = Math.floor(Math.random() * colors.length);
87 return colors[random];
88}
89
90function generateRandomColors(num){
91 //make an array
92 var arr = []
93 //repeat num times
94 for(var i = 0; i < num; i++){
95 //get random color and push into arr
96 arr.push(randomColor())
97 }
98 //return that array
99 return arr;
100}
101
102function randomColor(){
103 //pick a "red" from 0 - 255
104 var r = Math.floor(Math.random() * 256);
105 //pick a "green" from 0 -255
106 var g = Math.floor(Math.random() * 256);
107 //pick a "blue" from 0 -255
108 var b = Math.floor(Math.random() * 256);
109 return "rgb(" + r + ", " + g + ", " + b + ")";
110}