The JavaScript window is the global object which is used to control the browser window lifecycle and perform various operations on it.
The global variable window usually represents the current browser window in which the code is running, is available in our JavaScript code, and can be directly accessed by using window literal.
A window can be a new window, a new tab, a frameset, or an individual frame created with JavaScript. Note that, Window is the object of the browser, it is not the object of javascript. The javascript objects are string, array, date, etc.
Using the JavaScript Window Object
Let's take a look at common properties and methods when using the window object.
Heads up: you can type window in your console, and you'll see a long list of methods and properties you can use.
There are lots of them, so, let's see some common ones:
Alert Method:
alert ('Hello World');
Note that, you can do windows.alert('Hello World'); but there is no need for that as the browser knows the window you can working with.
Prompt Method
prompt('Enter Your name');
You can even alert whatever user enters in the prompt:
let input = prompt('Enter Your Name');
alert(input);
Confirm Method
// Confirm
if(confirm('Are you sure')){ // If user click OK
console.log('You Clicked Yes'); // log YES in console
} else { // If User click cancel, do below
console.log('You clicked No'); // Log No in Console
}
All we've been looking at so far are methods in the window object, we can also look at properties, for example, getting height of a browser.
Height and Width Properties
// Outter height and width
console.log(window.outerHeight); // => 728
console.log(window.outerWidth); // => 1366
// Inner height and width
console.log(window.innerHeight); // => 283
console.log(window.innerWidth); // => 1366
These are my window height, and width, so, yours might be different. You can use this property to target a specific height and width, and then do something on that specific height and width.
If you resize your browser window and rerun the code, you'll get a different height and width, depending on how far you resize it. Outer is for the outer edges and inner is within the window itself. So, here is an illustration between outer and inner height:
I hope that clarifies things. So, if I resize the console tab all the way up, the inner height is gonna change but the outer height won't change.
Scroll Point Properties
If say you want to figure out where you are in terms of scrolling, you can do:
console.log(window.scrollY); // Vertical Scroll
console.log(window.scrollX); // Horizontal Scroll
It would return 0 if there is no scroll bar. You can use the scroll properties with animation, for example, a scroll to top button should only show when you've scrolled down a bit.
Location Object
There are tons of objects within the window object, and an example is the location object. Enter window.location
in your console to see the methods and properties you can play with in the location object, here are examples of properties, you can play with:
// Location Object
// Assuming the url of the page is http://localhost:63342/jsapp/index.html?_ijt=hijbkvldqfj8olu115dio4177l
// You get:
console.log(window.location.hostname); // => localhost
console.log(window.location.port); // => 63342
console.log(window.location.pathname); // => /jsapp/index.html
console.log(window.location.protocol); // => http:
console.log(window.location.href); // => http://localhost:63342/jsapp/index.html?_ijt=hijbkvldqfj8olu115dio4177l
console.log(window.location.search); // => ?_ijt=hijbkvldqfj8olu115dio4177l // The search query string
There are also methods:
window.location.reload(); // This would keep reloading the browser, you can implement a button for this instead of doing it this way\
You can also redirect like so:
window.location.href = 'https://devsrealm.com';
This would take you to the above URL once you run the script. What happened here is that we took the href value, and reset it to another value, which then redirects to a new URL once the script is executed.
History Object
The history object is used to get browser history. Here is an example:
window.history.go(-1); // Goto the first previous history
window.history.go(-2); // Goto the second previous history
console.log(window.history.length); // => 10, 10 sites behind the page
Navigator Object
The Navigator interface represents the state and the identity of the user agent. It allows scripts to query it and to register themselves to carry on some activities. The navigator object has to do with the browser itself and not the window, e.g Chrome, Safari, and the like.
Here is an example:
// Navigator Object
console.log(window.navigator.appName); // => Netscape
console.log(window.navigator.appVersion); // => 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36
console.log(window.navigator.userAgent); // => Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36
console.log(window.navigator.platform); // => Win32
console.log(window.navigator.product); // => Gecko
console.log(window.navigator.vendor); // => Google Inc.
console.log(window.navigator.language); // => en-US
You can find more properties by typing window.navigator in the console.
Document Object
The browser gives us a window object and inside the window objects there are a couple of other objects, and a good example of that is the document object.
This is really easy to understand, as, with other objects, it can contain, properties, methods, and even another nested object.
The Document interface or object represents any web page loaded in the browser and serves as an entry point into the web page's content, which is the DOM tree. The DOM tree includes elements such as <body>, <table>, <li>, among many others. It provides functionality globally to the document, like how to obtain the page's URL and create new elements in the document.
We can use JavaScript to read, write, and manipulate the DOM. The DOM represents the HTML document as a tree of nodes. Every node represents a portion of the document.
here is an image illustration of the DOM Tree:
The image illustration is really straightforward, and I guess you understand it. If you don't here is a brief explanation:
- The document is the object
- Once we get access to the document object, we can then access the HTML, which is the root element
- The Head and Body are both siblings, they are also elements
- The others are just children of the element
Let's take an example:
We would be using the following structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SimpleApp</title>
<link rel="stylesheet" href="http://simpleapp.com/css/halfmoon-variables.min.css">
<link rel="stylesheet" href="http://simpleapp.com/css/app.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
<title>SimpleApp</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
</head>
<body class="antialiased">
<div class="content-wrapper text-center">
<div class="container-fluid">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card bg-light">
<div class="card-body">
<h4 class="card-header">Dashboard</h4>
You are logged in!, the_devsrealm_guy
</div>
<div class="container-fluid">
<div class="row justify-content-lg-start">
<div class="col-6 col-sm-5 col-md-4 col-lg-3 m-auto">
<h4>Posts</h4>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-3 m-auto">
<div class="form-group">
<label for="task" class="required w-100"></label>
<input type="text" class="form-control " id="task" placeholder="Something" name="email" value="" autofocus>
<input type="submit" value="Add Task" class="btn mt-10">
</div>
</div>
</div>
</div>
<!-- First row -->
<div class="row justify-content-lg-start">
<div class="col-12 col-sm-5 col-md-4 col-lg-3">
Almost Done With Our Application
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/25/edit" class="btn btn-primary">Edit</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/25" target="_blank" rel="noopener" class="btn btn-primary">View Post</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<form method="POST" action="http://simpleapp.com/posts/25" accept-charset="UTF-8" class="pull-right"><input name="_token" type="hidden" value="Ph2PQpUdxJHuoxUkHb892VfbfR0fuYHY60V2iW5a">
<input name="_method" type="hidden" value="DELETE">
<input class="btn btn-danger" type="submit" value="Delete">
</form>
</div>
</div>
<!-- First row -->
<div class="row justify-content-lg-start">
<div class="col-12 col-sm-5 col-md-4 col-lg-3">
Test Mastering Plugin New
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/26/edit" class="btn btn-primary">Edit</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/26" target="_blank" rel="noopener" class="btn btn-primary">View Post</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<form method="POST" action="http://simpleapp.com/posts/26" accept-charset="UTF-8" class="pull-right"><input name="_token" type="hidden" value="Ph2PQpUdxJHuoxUkHb892VfbfR0fuYHY60V2iW5a">
<input name="_method" type="hidden" value="DELETE">
<input class="btn btn-danger" type="submit" value="Delete">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="main.js" ></script>
</body>
</html>
I am using Halfmoon CSS framework, here is an example of how the page looks:
Don't forget to include the js file.
If you type window.document in your console, it would return the complete structure of the HTML. Here is an example of how to get some properties:
/*
1.) HTML Collection from Entire Document
=> [html, head, meta, meta, title, link, link, link, title, link, link, body.antialiased, div.content-wrapper.text-center...]
*/
console.log(document.all);
/*
2.) Access Certain Items in the Collection
=> <title>SimpleApp</title>
*/
console.log(document.all[4]);
/*
3.) Get the Lenght of the elements in the DOM
=> 52
*/
console.log(document.all.length);
/*
4.) Get The Head Element: This would return the head, and anything within the head tag
=> <head>...</head>
*/
console.log(document.head);
/*
5.) Get the Body Element: This would return the body, and anything within the body tag
=> <body>...</body>
*/
console.log(document.body);
/*
6.) Get the Doc Type
=> <!DOCTYPE html>
*/
console.log(document.doctype);
/*
7.) Get The Domain Name
=> localhost
*/
console.log(document.domain);
/*
8.) Get The Full URL
=> http://localhost:63342/jsapp/index.html
*/
console.log(document.URL);
/*
9.) Get The Character Set
=> UTF-8
*/
console.log(document.characterSet);
/*
10.) Get The Comtent Type
=> text/html
*/
console.log(document.contentType);
You can also select stuff directly, although we would typically use selectors for this, but for now, here is how you can do it:
Let's say, I want to access all the link element, I can first return the link collection using:
document.links
HTMLCollection(4) [a.btn.btn-primary, a.btn.btn-primary, a.btn.btn-primary, a.btn.btn-primary]
If I want to work on the first index of the item, I can do something like so:
console.log(document.links[0]); // => <a href="/posts/25/edit" class="btn btn-primary">Edit</a>
console.log(document.links[0].id); // => " " // Empty, means there is no id property in the index 0 of the link
console.log(document.links[0].className); // => btn btn-primary
console.log(document.links[0].classList[0]); // => btn, first index of the classes
If I access index 1, I'll get a different value:
console.log(document.links[1]); // => <a href="/posts/25" target="_blank" rel="noopener" class="btn btn-primary">View Post</a>
console.log(document.links[1].className); // => btn btn-primary
console.log(document.links[1].classList[0]); // => btn, first index of the classes
You see how easy it is to select data.
HTMLCollections are different from arrays, they are just formatted in a similar way, by default you won't be able to use loops, however, you can convert it into an array, which you can then loop through if you like:
let lnks = document.links;
let lnksArr = Array.from(lnks); // Convert the lnks collection to an array object
console.log(typeof lnksArr); // => object // array is an object
console.log(lnksArr); // => [a.btn.btn-primary, a.btn.btn-primary, a.btn.btn-primary, a.btn.btn-primary]
DOM Selector For Single Element
The Selectors API provides methods that make it quick and easy to retrieve Element nodes from the DOM by matching against a set of selectors. This is much better and faster without the use of jquery or other techniques, where you use a loop to locate the specific items you needed to find. With the Selectors API, you can select element nodes pretty easily.
The selector is a method in the document object. They are mainly two methods for selecting element:
- querySelector() - Returns the first matching Element node within the node's subtree. If no matching node is found, null is returned.
- querySelectorAll() - Returns a NodeList containing all matching Element nodes within the node's subtree, or an empty NodeList if no matches are found.
We would be focusing on the querySelector(), as that is all we need to select a single element. The selector methods accept one or more comma-separated selectors to determine what element or elements should be returned. Here are examples:
Note: I am using the HTML Structure I created above
console.log(document.querySelector('h4')); // => <h4 class="card-header">Dashboard</h4>
console.log(document.querySelector('.card.bg-light')); // => <div class="card bg-light">...</div>
If for example, you want to chang the content of the h4, you can do:
console.log(document.querySelector('h4')); // => <h4 class="card-header">Dashboard</h4>
let heading = document.querySelector('h4');
heading.textContent = 'Changed';
You can even style it:
console.log(document.querySelector('h4')); // => <h4 class="card-header">Dashboard</h4>
// console.log(document.querySelector('.card.bg-light')); // => <div class="card bg-light">...</div>
let heading = document.querySelector('h4');
heading.innerHTML = '<span style="color:#ec3054">Changed</span>';
Here is a simple HTML Structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SimpleApp</title>
<link rel="stylesheet" href="http://simpleapp.com/css/halfmoon-variables.min.css">
<link rel="stylesheet" href="http://simpleapp.com/css/app.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
<title>SimpleApp</title>
</head>
<body class="antialiased">
<div class="content-wrapper text-center">
<ul>
<li>Number 1</li>
<li>Number 2</li>
<li>Number 3</li>
<li>Number 4</li>
</ul>
</div>
<script src="main.js" ></script>
</body>
</html>
Here is how it looks:
The following would set the first list item to color blue:
document.querySelector('ul li').style.color = 'blue';
Remember, querySelector is used for selecting one element. We can also use CSS pseudo-classes like so:
document.querySelector('ul li:last-child').style.color = 'red'; // Set Last Li item to red
document.querySelector('ul li:nth-child(2)').style.color = 'green'; // Set second li item to green
document.querySelector('ul li:nth-child(3)').textContent = 'Hello World'; // Change thir li item to "Hello World"
We can also use odd and even pseudo-classes:
document.querySelector('ul li:nth-child(odd)').style.background = '#ea1d1d'; // Style the first odd li
document.querySelector('ul li:nth-child(even)').style.background = '#ff651a'; // style the first even li
Again, this would only target a single element. Before we proceed, I just want to mention, there is also getElementById(), which is for selecting ID. You really do not need this as you can do the selection with the querySelector() method. If you are curious, here is how to use the method:
HTML Structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SimpleApp</title>
<link rel="stylesheet" href="http://simpleapp.com/css/halfmoon-variables.min.css">
<link rel="stylesheet" href="http://simpleapp.com/css/app.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
<title>SimpleApp</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
</head>
<body class="antialiased">
<div id ="container" class="content-wrapper text-center">
<!--<div class="container-fluid">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card bg-light">
<div class="card-body">
<h4 class="card-header">Dashboard</h4>
You are logged in!, the_devsrealm_guy
</div>
<div class="container-fluid">
<div class="row justify-content-lg-start">
<div class="col-6 col-sm-5 col-md-4 col-lg-3 m-auto">
<h4>Posts</h4>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-3 m-auto">
<div class="form-group">
<label for="task" class="required w-100"></label>
<input type="text" class="form-control " id="task" placeholder="Something" name="email" value="" autofocus>
<input type="submit" value="Add Task" class="btn mt-10">
</div>
</div>
</div>
</div>
<!– First row –>
<div class="row justify-content-lg-start">
<div class="col-12 col-sm-5 col-md-4 col-lg-3">
Almost Done With Our Application
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/25/edit" class="btn btn-primary">Edit</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/25" target="_blank" rel="noopener" class="btn btn-primary">View Post</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<form method="POST" action="http://simpleapp.com/posts/25" accept-charset="UTF-8" class="pull-right"><input name="_token" type="hidden" value="Ph2PQpUdxJHuoxUkHb892VfbfR0fuYHY60V2iW5a">
<input name="_method" type="hidden" value="DELETE">
<input class="btn btn-danger" type="submit" value="Delete">
</form>
</div>
</div>
<!– First row –>
<div class="row justify-content-lg-start">
<div class="col-12 col-sm-5 col-md-4 col-lg-3">
Test Mastering Plugin New
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/26/edit" class="btn btn-primary">Edit</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/26" target="_blank" rel="noopener" class="btn btn-primary">View Post</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<form method="POST" action="http://simpleapp.com/posts/26" accept-charset="UTF-8" class="pull-right"><input name="_token" type="hidden" value="Ph2PQpUdxJHuoxUkHb892VfbfR0fuYHY60V2iW5a">
<input name="_method" type="hidden" value="DELETE">
<input class="btn btn-danger" type="submit" value="Delete">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>-->
<ul>
<li>Number 1</li>
<li>Number 2</li>
<li>Number 3</li>
<li>Number 4</li>
</ul>
</div>
<script src="main.js" ></script>
</body>
</html>
Using getElementbyId():
// For getElementById
console.log(document.getElementById('container')); // => <div id ="container" class="content-wrapper text-center">...</div>
// Get things from the element
console.log(document.getElementById('container').id); // => container
console.log(document.getElementById('container').className); // => content-wrapper text-center
// Change styling
let content = document.getElementById('container');
content.style.background = '#333';
content.style.color = '#fff';
content.style.padding = '25px';
// content.style.display = 'none';
// Change Content
content.textContent = 'Hello World'; // => Would replace all the list item with 'Task List'
content.innerHTML = '<span style="color:red">Hey</span>'; // => replaces all the InnerHTML with the span tags.
DOM Selector For Multiple Element
There are two ways, you can do this, you can either use getElementsByClassName() or the querySelectorAll() method.
Let's start with the first one: getElementsByClassName():
HTML Structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SimpleApp</title>
<link rel="stylesheet" href="http://simpleapp.com/css/halfmoon-variables.min.css">
<link rel="stylesheet" href="http://simpleapp.com/css/app.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
<title>SimpleApp</title>
</head>
<body class="antialiased">
<div id ="container" class="content-wrapper text-center">
<ul>
<li class="items">Number 1</li>
<li class="items">Number 2</li>
<li class="items">Number 3</li>
<li class="items">Number 4</li>
</ul>
</div>
<script src="main.js" ></script>
</body>
</html>
I added a class items to all of the li tags, to return a collection of that using getElementsByClassName, I can do:
// For getElementsByClassName
console.log(document.getElementsByClassName('items'));
// =>
HTMLCollection(4) [li.items, li.items, li.items, li.items]
0: li.items
1: li.items
2: li.items
3: li.items
length: 4
That is what the console. gave me, and we infact have 4 items. To get the first item, you reference the index 0 like so:
// For getElementsByClassName
let items = document.getElementsByClassName('items');
console.log(items[0]);
// =>
// <li class="items">Number 1</li>
Easy enough right, because the getElementsByClassName returns a collection of items, I can loop through it:
Here is the structure of a for loop:
for (init; test; increment) {
statement;
}
and we can loop through the collection items by testing the length, something like this:
let items = document.getElementsByClassName('items');
for (let i = 0; i < items.length ; i++) {
console.log(items[i]);
}
// => Output
// <li class="items">Number 1</li>
// <li class="items">Number 2</li>
// <li class="items">Number 3</li>
// <li class="items">Number 4</li>
Easy enough, we didn't even have to convert to an array to loop, and that is because we have a length property in our HTMLcollection we can run test against. So, the for loop is saying as long as i is lesser than the length of items in the collection, print the items, and increment the counter at each run.
Using a for of loop, you can also achieve the same thing:
for( let number of items) {
console.log(number);
}
The only thing you won't be able to do is using array functions, and I think forEach loop, but you can use all other loops without an issue.
To style the elements while looping, we can do:
let items = document.getElementsByClassName('items');
for( let number of items) {
number.style.color = 'red';
}
This would give us:
Using for loop, we can do the same thing:
let items = document.getElementsByClassName('items');
for (let i = 0; i < items.length ; i++) {
items[i].style.color = 'blue';
}
Easy enough, I guess. To change the element content, you can do:
let items = document.getElementsByClassName('items');
for (let i = 0; i < items.length ; i++) {
items[i].textContent = 'Hello World';
if (items[2]) {
items[2].textContent = 'This is the third index';
}
}
If you want to target a nested elements, you can do:
let items = document.querySelector('ul').getElementsByClassName('items');
console.log(items);
// => Output
/*
HTMLCollection(4) [li.items, li.items, li.items, li.items]
0: li.items
1: li.items
2: li.items
3: li.items
length: 4
*/
Same as using getElementsByClassName('items') directyly, but doing the above gives you a targeted parent element and it children.
There is also getElementsByTagName:
let lis = document.getElementsByTagName('li');
console.log(lis);
// => Output
/*
HTMLCollection(4) [li.items, li.items, li.items, li.items]
0: li.items
1: li.items
2: li.items
3: li.items
length: 4
*/
This is similar to getElementsByClassName, the only difference is we are selecting by tag name, useful in cases where you want to style multiple tag elements.
If you want to use an array function, then you might want to convert HTLM collection into an array, you can do it like so:
let items = document.querySelector('ul').getElementsByClassName('items');
// Convert HTML Collection into array
items = Array.from(items);
console.log(typeof items) // => objects // array is an object
// Using reverse function, which is used with an array items
items.reverse();
// Using For Each Loop: You can only use this with an Array.
items.forEach(function(items, index){ // index help us to track of the array indexes
console.log(items.className);
items.textContent = `${index}: Hello`;
});
// => Output:
Anotherway we can select multiple element is using the querySelectorAll, it is kinda like same as getElementsByClassName, the differences is that would return a NodeList instead of an HTMLCollection, you can even select an ID, here are examples:
let items = document.querySelectorAll('li.items');
console.log(items);
// => Output
/*NodeList(4) [li.items, li.items, li.items, li.items]
0: li.items
1: li.items
2: li.items
3: li.items
length: 4*/
You can use for, for of loop, and while loop to iterae over the Nodelist:
let items = document.querySelectorAll('li.items');
for( let number of items) {
number.style.color = 'red';
}
Unlike querySelector where it is only going to select a single element when using pseudo-classes e.g odd, you can select multiple pseudo-class with querySelectorAll:
let liOdd = document.querySelectorAll('li:nth-child(odd)');
let liEven = document.querySelectorAll('li:nth-child(even)');
for(let i = 0; i < liEven.length; i++){ // Set Background Color For All Even li items
liEven[i].style.background = '#bad245';
}
for(let i = 0; i < liOdd.length; i++){ // Set Background Color For All ODD li items
liOdd[i].style.background = '#b5b5a9';
}
Unlike the getElementsByClassName where we need to convert the HTMLCollection to an array before we can use an array function, you don't need that with querySelectorAll, it is a NodeList, and you can use any array function just fine without the need of converting:
// document.querySelectorAll
let items = document.querySelectorAll('li.items');
items.forEach(function(item, index){
item.textContent = `${index}: Hello`;
});
Traversing The DOM
Traversing is moving up and down the elements in the DOM. If for example, you select a parent element, you can access its children easily. Here is an example of how it works:
First let's select a parent ul:
let list = document.querySelector('ul');
console.log(list);
// => Output
/*
<ul>
<li class="items">Number 1</li>
<li class="items">Number 2</li>
<li class="items">Number 3</li>
<li class="items">Number 4</li>
</ul>*/
To get the childnode, we can do:
let list = document.querySelector('ul');
console.log(list.childNodes);
// => Output
/*NodeList(9) [text, li.items, text, li.items, text, li.items, text, li.items, text]
0: text
1: li.items
2: text
3: li.items
4: text
5: li.items
6: text
7: li.items
8: text
length: 9*/
You would expect the result to only output - li.items, but the reason it also includes text items is because of the line breaks in the li tags, if you remove the line break like so:
<ul>
<li class="items">Number 1</li><li class="items">Number 2</li><li class="items">Number 3</li><li class="items">Number 4</li>
</ul>
and rerun the code, you'll get:
let list = document.querySelector('ul');
console.log(list.childNodes);
// => Output
/*NodeList(6) [text, li.items, li.items, li.items, li.items, text]
0: text
1: li.items
2: li.items
3: li.items
4: li.items
5: text
length: 6*/
The first text is the line break before the li, and the second break is the line break after the li, you really don't have to remove line breaks, you can run the following instead to get the child node without having to remove line breaks:
let list = document.querySelector('ul');
console.log(list.children);
// => Output
/*HTMLCollection(4) [li.items, li.items, li.items, li.items]
0: li.items
1: li.items
2: li.items
3: li.items
length: 4*/
Haha, easy right. Caution: childnodes return a node list, and children returns HTMLCollection.
For nodes, you can also do:
console.log(list.childNodes[1]); // => <li class="items">Number 1</li>
console.log(list.childNodes[1].nodeName); // => LI
console.log(list.childNodes[0].nodeType); // => 3
console.log(list.childNodes[1].nodeType); // => 1
console.log(list.childNodes[2].nodeType); // => 1
console.log(list.childNodes[3].nodeType); // => 1
The nodeType has a number that corresponds to a certain nodes, it is a property or an integer that identifies what the node is. It distinguishes different kind of nodes from each other, such as elements, text and comments. Here are list of them:
/*
1 - Element Node - An Element node like <p> or <div>.
2 - Attribute Node - An Attribute of an Element
3 - Text Node - The actual Text inside an Element or Attr.
4 - CDATA Section node - A CDATASection, such as <!CDATA[[ … ]]>.
7 - Processing Instruction Node - A ProcessingInstruction of an XML document, such as <?xml-stylesheet … ?>
8 - Comment Node - A Comment node, such as <!-- … -->.
9 - Document Node - The Document itself
10 - Doctype Node - A DocumentType node, such as <!DOCTYPE html>.
*/
So, child node can return different type of nodes, not just Element, hope you get that.
For children also, you can select a certain children, you replace them, here is an example:
console.log(list.childrenn[1]); // => <li class="items">Hello</li>
list.children[1].textContent = 'Hey'; // => This would replacet the second index of li item with Hello
You can even get children of children, let's say I have the following HTML structure:
..............
..............
<ul>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 2</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 3</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 4</a>
</li>
</ul>
................
...............
a tag is the children children of ul, so, to get that, I can do:
// Children of Children
console.log(list.children[2].children[0]); // => <a href="/posts/25/edit" class="btn btn-primary">Number 3</a>
This means, select the children 0 of children 2 of the ul: ul>li>a
I can even replace the ClassName:
val = list.children[2].children[0].className = 'replace-that-shit';
console.log(list.children[2].children[0]); // => <a href="/posts/25/edit" class="replace-that-shit">Number 3</a>
To dynamically add an id, we can do:
val = list.children[2].children[0].id = 'new-id';
console.log(list.children[2].children[0]); // => <a href="/posts/25/edit" class="btn btn-primary" id="new-id">Number 3</a>
Here are other stuff you could do:
// First child
console.log(list.firstChild); // => #text
console.log(list.firstElementChild); // => <li class="items"><a href="/posts/25/edit" class="btn btn-primary">Number 1</a></li>
// Last child
console.log(list.lastChild); // => #text
console.log(list.lastElementChild); // => <li class="items"><a href="/posts/25/edit" class="btn btn-primary">Number 4</a></li>
// Count child elements
console.log(list.childElementCount); // => 4
If for example,you select the li:
let list = document.querySelector('li');
You can get the Parent node like so:
let liItem = document.querySelector('li');
console.log(liItem.parentNode); // => <ul>...</ul>
console.log(liItem.parentElement); // => <ul>...</ul> // same as above
console.log(liItem.parentElement.parentElement); // => <div id="container>...</div>
We can also get siblings, if the HTML Structure is:
..............
..............
<ul>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 2</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 3</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 4</a>
</li>
</ul>
................
...............
Then, console.log(liItem.nextSibling);
would give us #text
which is the next line break after the first li tag, if you don't want to deal with linebreak, just use:
console.log(liItem.nextElementSibling); // => <li class="items"><a href="/posts/25/edit" class="btn btn-primary">Number 2</a></li>
It would give us li number 2, we can move one step at a time by doing:
console.log(liItem.nextElementSibling.nextElementSibling.nextElementSibling); // => <li class="items"><a href="/posts/25/edit" class="btn btn-primary">Number 4</a></li>
The above moves one step at a time, li number 2, number 3, and number 4.
We also have previous, which you might have guessed it goes up:
console.log(liItem.previousSibling); // => #text
console.log(liItem.previousElementSibling); //=> null // this is because it doesn't exist
The first returns #text, which is the previous line break before the first li tag.
The previousElementSibling returns null because there is no previous li item.
You can also combine both together:
// Next and Prev
console.log(liItem.nextElementSibling.previousElementSibling); // => <li class="items"><a href="/posts/25/edit" class="btn btn-primary">Number 1</a></li>
It would first goto the second li, and back to the first.
You can see how easy it is to traverse an element. Now, let's put things to practice
Creating an Element
To create an element, you use the document.createElement() method, it takes a tagName parameter like so:
// Create Element
let li = document.createElement('li');
console.log(li); // => <li></li>
To add a class:
// Add a Class
let li = document.createElement('li');
li.className = 'items';
console.log(li); // => <li class="items"></li>
To add an id coupled with a class
// Add a ID
let li = document.createElement('li');
li.className = 'items';
li.id = 'an-id';
console.log(li); // => <li class="items" id="an-id"></li>
To set an Attribute:
// Add an Attribute
let li = document.createElement('li');
li.className = 'items';
li.setAttribute('title', 'New Item');
console.log(li); // => <li class="items" title="New Item"></li>
Append a Text
To put something in the middle of the li tags, you do:
// Create a Node and Append
let li = document.createElement('li');
li.className = 'items';
li.appendChild(document.createTextNode('Append Me'));
console.log(li); // => <li class="items">Append Me</li>
Creating a link element
// Create new link element
let link = document.createElement('a');
// Add classes
link.className = 'btn btn-primary';
console.log(link); // => <a class="btn btn-primary"></a>
Add an InnerHTML to link element
// Create new link element
let link = document.createElement('a');
// Add classes
link.className = 'btn btn-primary';
// Add inner html, useful for adding icon
link.innerHTML = '<i class="fa fa-remove"></i>';
console.log(link); // => <a class="btn btn-primary"><i class="fa fa-remove"></i></a>
Append link to li element
// Create Element
let li = document.createElement('li');
// Add classes to li
li.className = 'items';
// Create new link element
let link = document.createElement('a');
// Add classes to link
link.className = 'btn btn-primary';
// # Append link into li #
li.appendChild(link);
console.log(li); // => <li class="items"><a class="btn btn-primary"></a></li>
Isn't this awesome, if you can master the basics of this, then you can create complex stuff on your own, just learn to master the basics.
Creating an Elements, and attaching it to the DOM node
If we have the following structure:
-------------
------------
<ul>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 2</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 3</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 4</a>
</li>
</ul>
---------------
---------------
Which looks like this:
To append li as a child to the ul, we can do:
/*
######################
# Create li Element #
#####################
*/
let li = document.createElement('li');
// Add classes to li
li.className = 'items';
/*
#######################
# Create link Element #
######################
*/
let link = document.createElement('a');
// Add classes to link
link.className = 'btn btn-primary';
// Append a text to li
link.appendChild(document.createTextNode('Number 5'));
// Append link into li
li.appendChild(link);
/*
############################
# Append li as child to ul #
###########################
*/
document.querySelector('ul').appendChild(li);
Doing that gives us:
Removing and Replacing Elements
Replacing a dom element is really simple, here are the steps you need to take to do that:
- Get the element you want to remove
- Define or create the new element you want to replace the element with
- Replace the element
Here is the HTML Strcuture:
-----------
-----------
<div class="container-fluid">
<h3 id ="heading" class="text-center">List of Items</h3>
<ul>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 2</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 3</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 4</a>
</li>
</ul>
</div>
-----------
-----------
To replace the element, I'll start by defining what I want to remove, in my case, I want to replace the h3 tag, so, I need to get it first:
/*
###################################
# Get H3 Element__Old Heading #
##################################
*/
let oldHeading = document.getElementById('heading');
console.log(oldHeading); // => <h3 id="heading" class="text-center">List of Items</h3>
Now, let's define the new element we want to replace it with:
/*
##########################################
# Define New H3 Element__New Heading #
#########################################
*/
let newHeading = document.createElement('h2'); // Create Element
newHeading.id = 'heading'; // Add id
newHeading.className = 'text-center'; // Add class
newHeading.appendChild(document.createTextNode('New Heading')); // New text node
// Which would give us:
console.log(newHeading); // => <h2 id="heading" class="text-center">New Heading</h2>
To replace the element, we need to get the parent of the element, which in our case is a div, we then replace the child with the new element like so:
/*
###################################
# Get H3 Element__Old Heading #
##################################
*/
let oldHeading = document.getElementById('heading');
/*
##########################################
# Define New H3 Element__New Heading #
#########################################
*/
let newHeading = document.createElement('h2'); // Create Element
newHeading.id = 'heading'; // Add id
newHeading.className = 'text-center'; // Add class
newHeading.appendChild(document.createTextNode('New Heading')); // New text node
/*
#######################################################################
# Get Parent__Would Be Use To Target The Child Element To Replace #
#####################################################################
*/
let heading_parent = document.querySelector('.container-fluid');
/*
#######################
# Replcae The Element #
######################
*/
heading_parent.replaceChild(newHeading, oldHeading);
and that gives us:
Easy enough, I guess.
Removing an element is even much simpler, before removing an element, you first get whatever element you want to remove, you then use the remove method:
// Get Element To Remove
let ls = document.querySelectorAll('li');
console.log(ls);
// => Output
/*NodeList(4) [li.items, li.items, li.items, li.items]
0: li.items
1: li.items
2: li.items
3: li.items
length: 4*/
// Remove list item
ls[0].remove(); // => This would remove the fisrt li item
ls[1].remove(); // => This would remove the second li item
We can even loop through, and remove everything at once:
// Get Element To Remove
let ls = document.querySelectorAll('li');
// Remove list item With For Loop
for(let i =0; i < ls.length; i++) {
ls[i].remove(); // => This would remove all the li item
}
Also, you can select the parent element, and remove its child, to do this, you need to get both the parent and the child first, you then remove it by passing the child index to remove in the removechild argument like so:
// Get Both The Parent and The Child
let listitem = document.querySelector('ul'); // parent
let ls = document.querySelectorAll('li'); // child
console.log(listitem); // => <ul>...</ul>
// Remove child element
listitem.removeChild(ls[2]); // This removes the third li item
You can also loop through, and remove everything at once:
// Get Both The Parent and The Child
let listitem = document.querySelector('ul'); // parent
let ls = document.querySelectorAll('li'); // child
console.log(listitem); // => <ul>...</ul>
// Remove list item With For Loop
for(let i =0; i < ls.length; i++) {
listitem.removeChild(ls[i]); // => This would remove all the li child item
}
Remember the querySelectorAll returns a nodelist, which is why I was able to test for the list (ls.length), and also pass it to the removeChild argument. You can do that with only the querySelector.
Classes and Attributes
Again, the rule of thumb is to first get what you want to remove or replace, you then manipulate the items in whatever way you see fit:
Classes:
// CLASSES
let firstli = document.querySelector('li:first-child'); // get only the first li
console.log(firstli); // => <li class="items"><a href="/posts/25/edit" class="btn btn-primary">Number 1</a></li>
let link = firstli.children[0]; // get the children of the first li
console.log(link); // => <a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
// Classes
console.log(link.className); // => btn btn-primary
console.log(link.classList);
// => Output:
/*
DOMTokenList(2) ["btn", "btn-primary", value: "btn btn-primary"]
0: "btn"
1: "btn-primary"
length: 2
value: "btn btn-primary"
*/
console.log(link.classList[0]); // => btn // The First class in the a link
// Add new class to the last index of the DOMTokenList
link.classList.add('new');
console.log(link); // => <a href="/posts/25/edit" class="btn btn-primary new">Number 1</a>
// Remove the class 'new'
link.classList.remove('new');
console.log(link); // => <a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
For Attributes
// Attributes
let firstli = document.querySelector('li:first-child'); // get only the first li
console.log(firstli); // => <li class="items">a href="/posts/25/edit" class="btn btn-primary">Number 1</a></li>
let link = firstli.children[0]; // get the children of the first li
console.log(link); // => <a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
val = link.getAttribute('href');
console.log(val); // => /posts/25/edit
To set a link attribute, you do:
// Attributes
let firstli = document.querySelector('li:first-child'); // get only the first li
let link = firstli.children[0]; // get the children of the first li. which is a tag
// SetAttributes -- Link Attribute
link.setAttribute('href', 'http://devsrealm.com'); // this changes the href link to devsrealm.com
console.log(link); // => <a href="http://devsrealm.com" class="btn btn-primary">Number 1</a>
To set a title attribute:
// SetAttributes -- Link Attribute
link.setAttribute('href', 'http://devsrealm.com'); // this changes the href link to devsrealm.com
// SetAttributes - Title Attribite
link.setAttribute('title', 'Devsrealm'); // This changes the title attribite to Devsrealm
console.log(link); // => <a href="http://devsrealm.com" class="btn btn-primary" title="Devsrealm">Number 1</a>
You can also check if an attributes exist, and also remove an attribute:
link.hasAttribute('title'); // Check if there is an attribute
link.removeAttribute('title'); // => removes an attribute
Event Listeners and Event Objects
Event Listener and Handler
You can use event listeners to listen to any event on any number of element, and act on that event. This is useful for interactive page building. For example, if the user selects a button on a webpage, you might want to respond to that action by displaying an information box.
In Javascript, the events are fired inside the browser window, and tend to be attached to a specific item that resides in it — this might be a single element, set of elements, the HTML document loaded in the current tab, or the entire browser window. There are many different types of events that can occur. For example:
- The user selects a certain element or hovers the cursor over a certain element.
- The user chooses a key on the keyboard.
- The user resizes or closes the browser window.
- A web page finishes loading.
- A form is submitted.
- An error occurs.
- etc.
This is the HTML Structure of what we would be working with:
-------------------
-------------------
<div id ="container" class="content-wrapper text-center">
<div class="container-fluid">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card bg-light">
<div class="card-body">
<h4 class="card-header">Dashboard</h4>
You are logged in!, the_devsrealm_guy
</div>
<div class="container-fluid">
<div class="row justify-content-lg-start">
<div class="col-6 col-sm-5 col-md-4 col-lg-3 m-auto">
<h4>Posts</h4>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-3 m-auto">
<div class="form-group">
<label for="task" class="required w-100"></label>
<input type="text" class="form-control " id="task" placeholder="Something" name="email" value="" autofocus>
<input type="submit" value="Add Task" class="btn btn-rounded mt-10 add-task">
<input type="submit" value="Clear All" class="btn btn-rounded mt-10 clear-all">
</div>
</div>
</div>
</div>
<!-- First row -->
<div class="row justify-content-lg-start">
<div class="col-12 col-sm-5 col-md-4 col-lg-3">
Almost Done With Our Application
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/25/edit" class="btn btn-primary">Edit</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/25" target="_blank" rel="noopener" class="btn btn-primary">View Post</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<form method="POST" action="http://simpleapp.com/posts/25" accept-charset="UTF-8" class="pull-right"><input name="_token" type="hidden" value="Ph2PQpUdxJHuoxUkHb892VfbfR0fuYHY60V2iW5a">
<input name="_method" type="hidden" value="DELETE">
<input class="btn btn-danger" type="submit" value="Delete">
</form>
</div>
</div>
<!-- First row -->
<div class="row justify-content-lg-start">
<div class="col-12 col-sm-5 col-md-4 col-lg-3">
Test Mastering Plugin New
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/26/edit" class="btn btn-primary">Edit</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<a href="/posts/26" target="_blank" rel="noopener" class="btn btn-primary">View Post</a>
</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-2 m-5">
<form method="POST" action="http://simpleapp.com/posts/26" accept-charset="UTF-8" class="pull-right"><input name="_token" type="hidden" value="Ph2PQpUdxJHuoxUkHb892VfbfR0fuYHY60V2iW5a">
<input name="_method" type="hidden" value="DELETE">
<input class="btn btn-danger" type="submit" value="Delete">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
-----------
-----------
Here is what it looks like:
Cool. Let's get our hands dirty:
I'll add an event listener to the Clear All button, it has a class of clear-all, I can select it like so:
val = document.querySelector('.clear-all');
console.log(val); // => <input type="submit" value="Clear All" class="btn btn-rounded mt-10 clear-all">
To add an event listener, you just add on to it like so:
document.querySelector('.clear-all').addEventListener('click', function (){
// The event listener function statement
});
It takes two parameters, the first is the type of event you want to listen to, in our case, its a click, and it also takes in an event handler or event listener.
Each available event has an event handler, which is a block of code that runs when the event fires. When such a block of code is defined to run in response to an event, we say we are registering an event handler. The listener listens out for the event happening, and the handler is the code that is run in response to it happening.
So, whatever we put in the function is what is going to happen when we run the click event on the DOM element: (.clear-all).
Here is an example that logs to console, when you click the Clear-all button:
In our case, we are using the input type to create the button: <input type="submit" value="Clear All" class="btn btn-rounded mt-10 clear-all">
If you are using say a link to create the button: <a href="google.com" class="btn btn-primary">Edit</a>
When you clicked the button, it would still log the string click to the console, but it would automatically redirect to google.com without you even noticing, this is because it is using the default behavior of the link element (which is to go to a page), if you put a dollar sign in the href value, it would disable the ability to go to a certain URL and would log the string "click" in the console just fine.
To disable this behavior, you can pass in an event object like so:
document.querySelector('.clear-all').addEventListener('click',
function (e){
console.log('clicked');
e.preventDefault(); // Prevent The Default View of the element
});
We don't need this since I am merely using an input type, but just want to show you in case you encounter the issue down the line.
Instead of using an anonymous function, we can use a named function by passing the name of the function to the second parameter of the addEventListener, and we then define the function anywhere we like, here is an example:
// When this event happens, it looks for a function called onClick, and runs whatever is there
document.querySelector('.clear-all').addEventListener('click', onClick);
function onClick (){
console.log('clicked');
}
This is more cleaner if you ask me. Here is an event and an handler that changes the background card color:
document.querySelector('.clear-all').addEventListener('click', onClick);
function onClick (){ // When user Clicks the element, and the type is of click, do below
background = document.querySelector('.card.bg-light');
classlist = background.classList; // get all the classlist
classlist.remove('bg-light') // remove .bg-light class list
classlist.add('bg-orange') // add a new classlist
background.style.backgroundColor = 'orange'; // Add an inline
console.log('clicked');
}
I had to remove the bg-light class so the inline class could take effect:
Before click the button:
After clicking the button:
You can see that it remove the bg-light class, and we added a new class named bg-orange, although it is not useful for now as it's no doing anything. The inline background style we added is the one changing the color.
Event Object
We've seen an event object in action before we passed e to our function, it can also be written as event, evt, or simply e (you can use any name you like e.g c, d, f, but e is common). The event object is automatically passed to event handlers to provide extra features and information.
To get a list of event object you can work with on that element, you can log them like so:
document.querySelector('.clear-all').addEventListener('click', onClick);
function onClick (e){ // When user Clicks the element, and the type is of click, do below
let val;
val = e;
console.log(e); // MouseEvent{...}...target: ....
}
This would return lots of event objects and properties, for now, let's look at the target.
The target represents the elements that the event happens on, here are some examples:
document.querySelector('.clear-all').addEventListener('click', onClick);
function onClick (e){ // When user Clicks the element, and the type is of click, do below
let val;
// Event target element
console.log(e.target); // => <input type="submit" value="Clear All" class="btn btn-rounded mt-10 clear-all">
console.log(e.target.id); // => ' ' // Emrty no ID
console.log(e.target.className); // => btn btn-rounded mt-10 clear-all
console.log(e.target.classList); // => DOMTokenList(4) ["btn", "btn-rounded", "mt-10", "clear-all", value: "btn btn-rounded mt-10 clear-all"]
// Event Type
console.log(e.type); // => click
// Coords event relative to the window -- The Value would depend on where you click on the element
console.log(e.clientY); // => 124
console.log(e.clientX); // => 398
// Coords event relative to the element
console.log(e.offsetY); // => 26
console.log(e.offsetX); // => 39
// Timestamp
console.log(e.timeStamp); // => 199.444ms The timeStamp Event interface returns the time (in milliseconds) at which the event was created.
}
Mouse Events
The MouseEvent represents events that occur when you interact with a point device, like mousing over a certain element. Common events using this interface include click, dblclick, mouseup, mousedown.
MouseEvent is part if the UIEvent, which in turn is part of the Event API. Here are examples with explanations:
let clear_btn = document.querySelector('.clear-all'); // The clear button
let card = document.querySelector('.card'); // The Card Section
let heading = document.querySelector('h4'); // The h4 element
// Let's Create an Event Handler
function runmouseevent(e) {
console.log(`Event Type: ${e.type}`);
}
// Doubleclick
/*
Once the user double click the clear_btn,
it would fire the event listener,
which would then return: Event Type: dblclick
*/
clear_btn.addEventListener('dblclick', runmouseevent);
// Mousedown
/*
Once the user click or click and hold,
it would fire the mousedown event, which would in turn run the
event handler, and that returns: Event Type: mousedown
*/
clear_btn.addEventListener('mousedown', runmouseevent);
// Mouseup
/*
Once the user clicks and release,
it would fire the mouseup event, which would in turn run the
event handler, and that returns: Event Type: mouseup
Note: If you do not release the click, it won't fire.
*/
clear_btn.addEventListener('mouseup', runmouseevent);
// Mouseenter
/*
This would fire as soon as you enter the card element
If you move your mouse out, and reenter the element body again, it would fire.
*/
card.addEventListener('mouseenter', runmouseevent);
// Mouseleave
/*
If you enter the card element, and go outside, i
t would fire the mouseleave event.
So, this practically means,
if the user is in the card element,
and as soon as the user mouses out of the card element, fire the event
*/
card.addEventListener('mouseleave', runmouseevent);
// Mouseover
/*
This is simple, the event would fire each time you mouseover
or hover the element
*/
card.addEventListener('mouseover', runmouseevent);
// Mouseout
/*
This won't fire an event if the mouse is in a child element of a parent element
But would fire everytime you hover or mouseover the parent element, in our case it is card element
<card>
<li></li>
<h2></h2>
</card>
If you go inside the li or the h2 element, it won't fire but would fire everytime you over around the card element.
*/
card.addEventListener('mouseout', runmouseevent);
// Mousemove
/*
This would fire an event for any movement around the element, be it a child element or child-child element
This can be used to run games or super interactive stuff
*/
card.addEventListener('mousemove', runmouseevent);
You can get the x and y co-ordinate by using the e.offsetX and e.offsetY in the event handler each time you mousemove, something like so:
let heading = document.querySelector('h3');
card.addEventListener('mousemove', runmouseevent);
// Event Handler
function runEvent(e) {
console.log(`EVENT TYPE: ${e.type}`);
heading.textContent= `MouseX: ${e.offsetX} MouseY: ${e.offsetY}`;
}
This would replace the heading content with the co-ordinates, here is an illustration:
Super handy for games and complex interactive stuff.
We can also use this to create random rgb colors, well, since rgb takes three values, we can change the body color based on where the mouse moves to:
let heading = document.querySelector('h3');
card.addEventListener('mousemove', runmouseevent);
// Event Handler
function runmouseevent(e) {
console.log(`EVENT TYPE: ${e.type}`);
heading.textContent= `MouseX: ${e.offsetX} MouseY: ${e.offsetY}`;
document.body.style.backgroundColor = `rgb(${e.offsetX}, ${e.offsetY}, 40)`;
}
The below is an illustration:
You can really build cool stuff with this ;)
KeyboardEvent API describes user interaction with the keyboard; each event describes a single interaction between the user and a key (or combination of a key with modifier keys) on the keyboard. The event type (keydown, keypress, or keyup) identifies what kind of keyboard activity occurred.
The thing is, KeyboardEvent events simply indicate what interaction the user had with a key on the keyboard at a low level, providing no contextual meaning to that interaction.
When you need to handle text input, use the input event instead. Keyboard events may not be fired if the user is using an alternate means of entering text, such as a handwriting system on a tablet or graphics tablet.
So, let's say I have the following HTML Structure:
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<h5 class="card-header">Login</h5>
<div class="card-body">
<form method="POST" action="http://simpleapp.com/login"
class="form-inline w-400 mw-full m-auto">
<input type="hidden" name="_token" value="CsNItbmZ7II1Kfxc3CKLaaLWbfD5INVtsuGV2WhW">
<div class="form-group">
<label for="email" class="required w-100">E-Mail Address</label>
<input type="email" class="form-control " id="email" placeholder="E-mail Address"
required="required" name="email" value="" required autocomplete="email"
autofocus>
</div>
<div class="form-group">
<label for="password" class="required w-100">Password</label>
<input type="password" class="form-control " id="password" required="required"
name="password" required autocomplete="new-password">
</div>
<div class="form-group row">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember">
<label class="form-check-label" for="remember">
Remember Me
</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
Login
</button>
<a class="btn btn-link" href="http://simpleapp.com/password/reset">
Forgot Your Password?
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
This gives us the following structure:
Cool.
Here are examples:
let form = document.querySelector('form');
function fireEvent(e){
console.log(`EVENT TYPE: ${e.type}`);
e.preventDefault(); // Prevent default behaviour of the submit button
}
form.addEventListener('submit', fireEvent); // submit event fires when a form is about to be submitted
Fill in the log in details, and when you click login, it would log the event type in the console.
Here is an illustration:
To get an input value, we can do:
// First Clear The input If There is any
userInput.value = '';
function fireEvent(e){
console.log(`EVENT TYPE: ${e.type}`);
console.log(userInput.value); // => This returns empty cos there is no input
}
To get a selector, and then replace it with whatever you type in the input, you can do:
let userInput = document.getElementById('email');
let heading = document.querySelector('h5');
userInput.addEventListener('keydown', fireEvent) // Add an event handler, I'll explain the keydown below
function fireEvent(e){
console.log(`EVENT TYPE: ${e.type}`);
heading.innerText = e.target.value;
}
In the function, we get the heading innerText, we then set it equals to the value of the event target, which means whatever, we type in the input would get replaced in realtime, here is an illustration:
These are other examples:
Note that the following examples would only work on the email input, since that is what we are getting:
let userInput = document.getElementById('email');
function fireEvent(e){
console.log(`EVENT TYPE: ${e.type}`);
}
// Keydown
/*
Fire the event once a key has been pressed
*/
userInput.addEventListener('keydown', fireEvent);
// Keyup
/*
Fire the event once A key has been released.
*/
userInput.addEventListener('keyup', fireEvent);
// Keypress - Deprecated // no longer recommended. Use Keydown instead
/*
Same as Keydown
*/
userInput.addEventListener('keypress', fireEvent);
The above are the key events, let's look at the input events:
let userInput = document.getElementById('email');
function fireEvent(e){
console.log(`EVENT TYPE: ${e.type}`);
}
// Focus
/*
Fires When you click inside of an input type and it is set to focus
*/
userInput.addEventListener('focus', fireEvent);
// Blur
/*
Fires when you click outside of an input box
*/
userInput.addEventListener('blur', fireEvent);
// Cut
/*
Fires When You Cut a text in an input box
*/
userInput.addEventListener('cut', fireEvent);
// Paste
/*
Fires When You paste a text in an input box
*/
userInput.addEventListener('paste', fireEvent);
Event Bubbling & Delegation
Let's start with event bubbling, Event bubbling is simply the bubbling of of events through the DOM. Let's say we have the following HTML structure:
<div>
<ul>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
<li class="items">
<a href="/posts/25/edit" class="btn btn-primary">Number 1</a>
</li>
</ul>
</div>
In an event bubble, the last child of the parent fires first, in this case, it is a, then it bubbles to li, to ul, and to the parent div. Here is what happens, if you click a, it would bubble up, all the way to its parent element which is div, if you click li, it would bubble up all the way to the parent element which is div, etc. Here is an illustration.
I hope you get that, now let's understand Event delegation. Instead of having listeners for all the elements, you can delegate a parent element as the listener for all the events that happens inside the child element, that is event delegation, it is much better than having to create a handler for every child element.
Now, here is the interesting part, Event delegation also uses event bubbling to bubble up the elements, but it does that for you, so, we can say event delegation is the auto-bubble up of an elements if the parent element is delegated as the listener, it is not like you add like a magical event delegation method you'll still need to build the logic of how it would handle it, but the good thing is, you build the logic in one handler.
In Which Scenario is Event Delegation Useful?
Imagine you have 50 list item, and you want to find out which item has been clicked, which you can then act on, there are two ways you can do this, the ugly way is adding a handler for all the list item, the simpler and faster method is to put them in a container, assign a click event type to this container, and use event.target to find out which list item has been clicked.
Another scenario where this is useful is if you want to dynamically add a new list item, you'll typically want to use event delegation to handle this.
Let's see an example:
<div class="card">
<ul>
<li class="item"> Number 1
<a href="#" class="btn btn-primary">
<i class="fa fa-remove"></i>
</a>
</li>
<li class="item"> Number 2
<a href="#" class="btn btn-primary">
<i class="fa fa-remove"></i>
</a>
</li>
<li class="item"> Number 3
<a href="#" class="btn btn-primary">
<i class="fa fa-remove"></i>
</a>
</li>
<li class="items"> Number 4
<a href="#" class="btn btn-primary">
<i class="fa fa-remove"></i>
</a>
</li>
</ul>
</div>
Which looks like this:
Let's create an event delegation that logs the word "deleted" in the console whenever the x icon has been clicked:
document.querySelector('.card').addEventListener('click', deleteItem);
function deleteItem(e) {
if (e.target.parentElement.className === 'btn btn-primary') {
console.log('deleted');
}
}
We use the querySelector to select the card element, what I did here is that I delegated a parent element as the listener for all the event that happens inside the child element.
Let me break down the deleteItem function, the e.target is used for returning the element that triggered the event, so since we added the .card element has the parent element, we can use e.target to get the child elemet that triggers the click event within the card,
I'll use the following code to log the e.target in the console:
document.querySelector('.card').addEventListener('click', deleteItem);
function deleteItem(e) {
console.log(e.target)
}
Here is an illustration as usual:
What about e.target.parentElement
? This means the parentElement of the target you clicked, if for example, we have:
<a href="#" class="btn btn-primary"> <i class="fa fa-remove"></i> </a>
and you click on the i element, then e.target.parentElement would trigger the a element, simple right.
Now, let's get back to the function:
function deleteItem(e) {
if (e.target.parentElement.className === 'btn btn-primary') {
console.log('deleted');
}
This means, if the className of the e.target.parentElement is strictly equals to btn btn-primary log the string "deleted" easy peasy. On a side note, if the className is btn btn-one btn-two, you must include it, if you only want to include just one className among other ones, you can use classList.contains method: e.target.parentElement.classList.contains('btn')
With that out of the way, let's create a script that removes an item once it is clicked using the stuff we've learnt above:
document.querySelector('.card').addEventListener('click', deleteItem);
function deleteItem(e) {
if (e.target.parentElement.classList.contains('btn')) {
e.target.parentElement.parentElement.remove();
}
}
If the structure is:
<li class="item"> Number 2 <a href="#" class="btn btn-primary"> <i class="fa fa-remove"></i> </a> </li>
and you click the i tag, e.target.parentElement.parentElement.remove() removes the li tag, 2 parents up. So, we first check if what the user clicks contains the btn class, we then remove the designated element, here is an illustration:
Cool.
This guide is getting way longer that expected, I'll conclude it here, and write future guide on a different page entirely.