As the web standards becoming more mature each day, my prediction is that the need for third-party JavaScript library such as jQuery will slowly decline. jQuery is indeed still one of the best client-side JavaScript library in my opinion and even I still use it on some of my projects, but as the web application becoming more complex, programmers will starting to look at browser's native solution which will (maybe) offers better performance than the third-party library. In this post i will show you some of the browser's native API for replacing jQuery's DOM selector method, the obvious "$" or "jQuery" function. Under the hood, jQuery is actually using Sizzle library for its DOM selector, which i believe (even though I haven't dig inside the source code) Sizzle also using some of the browser's native API.
DOM selector with document.querySelector(selectors)
As the name already suggests, this method under the Document object fetch the first element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned. One important thing that we need to know here is that, using this method will return "null" value when no matches were found. For those who familiar with jQuery need to pay attention as the jQuery selector always returns empty Array when no matches were found. Below I show you some example.
<!doctype html>
<html><head><title>Query Selector in JavaScript</title><meta charset="UTF-8"></head>
<body>
<div>This is the first DIV</div>
<div>This is the second DIV</div>
<div>This is the third DIV</div>
<div>This is the fourth DIV</div>
<div>This is the fifth DIV</div>
<script>
// get the first DIV
let firstDiv = document.querySelector('div');
console.log('This is ', firstDiv);
// get the second DIV
let secondDiv = document.querySelector('div:nth-of-type(2)');
console.log('This is the ', secondDiv);
// change the text color to blue
secondDiv.style.color = 'blue';
// get the third DIV
let thirdDiv = document.querySelector('div:nth-of-type(3)');
console.log('This is the ', thirdDiv);
// change the text format to bold
thirdDiv.style.fontWeight = 'bold';
// check if element exists
let sixthDiv = document.querySelector('div:nth-of-type(6)');
if (sixthDiv == null) {
// add the sixth div if it is not exists yet
let newDiv = document.createElement("div")
newDiv.innerText = 'This is the sixth DIV';
document.body.append(newDiv);
}
</script>
</body>
</html>
Tree traversal
querySelector
method accepts all type of CSS selector and can be used to do DOM element tree traversal. In fact I already showed one of it the first example using nth-of-type(n)
modifier. You can of course use parent children relationship selector also in this case.
<!doctype html>
<html><head><title>Query Selector in JavaScript</title><meta charset="UTF-8"></head>
<body>
<div id="parent">
<div class="child">
<div class="grandchild">
<div class="great_grandchild"></div>
</div>
</div>
<div class="child">
<div class="grandchild"></div>
</div>
</div>
<script>
/* TREE TRAVERSAL */
// get the first direct child under parent
let firstChild = document.querySelector('#parent > .child');
console.log('This is the ', firstChild);
// get the great grandchild under parent
let greatGrandChild = document.querySelector('#parent .great_grandchild');
console.log('This is the ', greatGrandChild);
// alternative syntax to get the great grandchild
greatGrandChild = firstChild.querySelector('.great_grandchild');
console.log('This is the ', greatGrandChild);
// add new first child under parent
let newFirstChild = document.createElement("div");
newFirstChild.innerText = 'The real 1st child';
document.querySelector('#parent').prepend(newFirstChild);
// get the parent of great grandchild
let parentOfGrandChild = greatGrandChild.parentNode;
console.log(parentOfGrandChild);
</script>
</body>
</html>
Multiple DOM element matches and manipulation with querySelectorAll
The querySelectorAll
method behaves almost similar with the querySelector
, except that it returns not only single match but an array in form of NodeList object instead. You can use this if you want to manipulate more than one element that match with your specified selector. Just remember to add :scope
pseudo class at the very first of selector string to make sure the browser only get the child element under the specified element.
<!doctype html>
<html><head><title>Query Selector in JavaScript</title><meta charset="UTF-8"></head>
<body>
<ul id="bio">
<li class="name">The first one</li>
<li class="location">Tsukuba, Japan</li>
<li class="name">The second one</li>
<li class="location">Tokyo, Japan</li>
<li class="name">The third one</li>
<li class="location">Jakarta, Indonesia</li>
<li class="name">The fourth one</li>
<li class="location">Seoul, South Korea</li>
<li class="name">The fifth one</li>
<li class="location">Wuhan, China</li>
</ul>
<script>
/* querySelectorAll */
// get all names
let names = document.querySelectorAll(':scope #bio .name');
console.log('Number of names ', names.length);
console.log('The elements are ', names);
// get all locations
let locations = document.querySelectorAll(':scope #bio .location');
console.log('The elements are ', locations);
// make all location texts italic
locations.forEach(e => e.style.fontStyle = 'italic');
// prepend "name" text inside name element
names.forEach(e => e.prepend('Name: '));
// add empty list element with bottom border after location
// as a data separator
locations.forEach(function(e){
let borderedList = document.createElement('li');
borderedList.style.borderBottom = '1px solid #999';
e.after(borderedList);
});
</script>
</body>
</html>
Pretty neat huh? :D
Sibling manipulation with previousElementSibling
and nextElementSibling
It is very often we want to manipulate DOM elements which are positioned on the same level as current selected element, or the siblings of current element. In this case we can use the previousElementSibling
and nextElementSibling
property.
<!doctype html>
<html><head><title>Query Selector in JavaScript</title><meta charset="UTF-8"></head>
<body>
<div id="friends">
<div class="friend">Harada</div>
<div class="friend">Sasaki</div>
<div class="friend">Iqbal</div>
<div class="friend">Michael</div>
<div class="friend">Megumi</div>
</div>
<script>
/* SIBLINGS */
// get iqbal
let iqbal = document.querySelector('#friends .friend:nth-of-type(3)');
console.log(iqbal);
// who is our friend before iqbal
let beforeIqbal = iqbal.previousElementSibling;
// change the color to orange
beforeIqbal.style.color = 'orange';
// who is our friend after iqbal
let afterIqbal = iqbal.nextElementSibling;
// change the color to purple
afterIqbal.style.color = 'purple';</script>
</body>
</html>