Learn JavaScript DOM by building a slider without html markups

Learn JavaScript DOM by building a slider without html markups

According to MDN:

The Document Object Model (DOM) is a programming interface for web documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as nodes and objects; that way, programming languages can interact with the page.

A web page is a document that can be either displayed in the browser window or as the HTML source. In both cases, it is the same document but the Document Object Model (DOM) representation allows it to be manipulated. As an object-oriented representation of the web page, it can be modified with a scripting language such as JavaScript.

The DOM is not part of the JavaScript language, but is instead a Web API used to build websites. JavaScript can also be used in other contexts. For example, Node.js runs JavaScript programs on a computer, but provides a different set of APIs, and the DOM API is not a core part of the Node.js runtime.

What we will be building

To understand the basics of JavaScript DOM, we will be building a slider. This slider would have two buttons that will handle the the next and previous displays.

Step 1: Create start markup

To create our start markup, we will create a new file; index.html and write the following codes in it. We will add a script tag that will point to script.js and this will have an attribute of type="module" so we can use ES6 module in it.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Slider</title>
  </head>
  <body>
    <div id="slider"></div>
    <script src="script.js" type="module"></script>
  </body>
</html>

Step 2: Create a file that holds our images url

We will create a data.js file and add the following image urls to it and export it as an object:

export const images = [
  "https://images.unsplash.com/photo-1648737965961-2280af0f2cf7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHw1MXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652489997208-87ffeffc072b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1MHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652700896351-3174534db580?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1NXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652703747774-558a10faacc2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1OHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652767050717-42f222b0e86b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw2NHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652752724447-c2ad8657dc39?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw2N3x8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652768787394-b7bca615acb3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw2OHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
];

Step 3: Create the main script that handles our slider

Here, we will begin by creating a script.js file that holds the whole logic for our DOM manipulation and slider. The first thing to do in this file is to import the array of images url from the data.js file, grab the slider Id from the HTML page and also create an imageIndex variable.:

import { images as imagesSrc } from "./data.js";
const sliderContainer = document.getElementById("slider");

let imageIndex = 0;

Next, we will create a function that generates an empty image for us. To achieve this, we will use the document.createElement("img") DOM method to create an image element. It is worthy to note that with this DOM method, you can create any HTML element such as p, span, form etc. We will store the newly created image in an img variable, and using the variable we can add styles and every other HTML attribute to the image. We will add the a heightand width of 300px each, objectFit of cover and also add the flex order of 2 which will help us position the image properly. Finally, we will return the img

function generateImage() {
  const img = document.createElement("img");
  img.style.width = 300 + "px";
  img.style.height = 300 + "px";
  img.style.objectFit = "cover";
  img.style.order = 2;
  return img;
}

Next, we create the next button. To achieve this, we will use the document.createElement("button") DOM method. We will store it in a variable named nextButton and with this we can add attributes to the newly created button. The first is the textContent which we will set to Next, followed by the order which we will set to 3. The next button will also listen to an onclick event that will fire a function. This function increments the imageIndex if it is not equal to the imageSrc length - 1. Finally we call the changeImageSrc() and passing the imageIndex variable to it. Note: The changeImageSrc function has not been created yet.

const nextButton = document.createElement("button");
nextButton.textContent = "Next";
nextButton.style.order = 3;
nextButton.onclick = function () {
  if (imageIndex === imagesSrc.length - 1) {
    imageIndex = 0;
  } else {
    imageIndex++;
  }
  changeImageSrc(imageIndex);
};

Next, we create the prev button. To achieve this, we will use the document.createElement("button") DOM method. We will store it in a variable named prevButton and with this we can add attributes to the newly created button. The first is the textContent which we will set to Prev, followed by the order which we will set to 1. The prev button will also listen to an onclick event that will fire a function. This function increments the imageIndex if it is not equal to the 0. Finally we call the changeImageSrc() and passing the imageIndex variable to it. Note: The changeImageSrc function has not been created yet.

const prevButton = document.createElement("button");
prevButton.textContent = "Prev";
prevButton.style.order = 1;
prevButton.onclick = function () {
  if (imageIndex === 0) {
    imageIndex = imagesSrc.length - 1;
  } else {
    imageIndex--;
  }
  changeImageSrc(imageIndex);
};

Next, we create a div and store it in a variable; imagesContainer. We will add a width of 100%, maxWidth of 370px, etc


const imagesContainer = document.createElement("div");
imagesContainer.style.width = "100%";
imagesContainer.style.maxWidth = "370px";
imagesContainer.style.padding = "20px";
imagesContainer.style.display = "flex";
imagesContainer.style.gap = "1rem";
imagesContainer.style.justifyContent = "center";
imagesContainer.style.alignItems = "center";

Next we append the img, nextButton and prevButton to the imagesContainer and also append the the imagesContainerto the sliderContainer

imagesContainer.appendChild(generateImage());
imagesContainer.appendChild(nextButton);
imagesContainer.appendChild(prevButton);
sliderContainer.append(imagesContainer);

Next we will create the the changeImageSrc function that accepts an index and from the imageSrc array get an image with that index. We will use the sliderContainer to select the image.

function changeImageSrc(index) {
  sliderContainer.childNodes[0].childNodes[0].src = imagesSrc[index];
}

Finally, we will set a default image on event listener of DOMContentLoaded

document.addEventListener("DOMContentLoaded", () => changeImageSrc(0));

Codes Combined

1- index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Slider</title>
  </head>
  <body>
    <div id="slider"></div>
    <script src="script.js" type="module"></script>
  </body>
</html>

2- data.js:

export const images = [
  "https://images.unsplash.com/photo-1648737965961-2280af0f2cf7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHw1MXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652489997208-87ffeffc072b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1MHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652700896351-3174534db580?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1NXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652703747774-558a10faacc2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1OHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652767050717-42f222b0e86b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw2NHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652752724447-c2ad8657dc39?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw2N3x8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
  "https://images.unsplash.com/photo-1652768787394-b7bca615acb3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw2OHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60",
];

3- script.js:

import { images as imagesSrc } from "./data.js";

const sliderContainer = document.getElementById("slider");

let imageIndex = 0;

function generateImage() {
  const img = document.createElement("img");
  img.style.width = 300 + "px";
  img.style.height = 300 + "px";
  img.style.objectFit = "cover";
  img.style.order = 2;
  return img;
}

const nextButton = document.createElement("button");
nextButton.textContent = "Next";
nextButton.style.order = 3;
nextButton.onclick = function () {
  if (imageIndex === imagesSrc.length - 1) {
    imageIndex = 0;
  } else {
    imageIndex++;
  }
  changeImageSrc(imageIndex);
};

const prevButton = document.createElement("button");
prevButton.textContent = "Prev";
prevButton.style.order = 1;
prevButton.onclick = function () {
  if (imageIndex === 0) {
    imageIndex = imagesSrc.length - 1;
  } else {
    imageIndex--;
  }
  changeImageSrc(imageIndex);
};

const imagesContainer = document.createElement("div");
imagesContainer.style.width = "100%";
imagesContainer.style.maxWidth = "370px";
imagesContainer.style.padding = "20px";
imagesContainer.style.display = "flex";
imagesContainer.style.gap = "1rem";
imagesContainer.style.justifyContent = "center";
imagesContainer.style.alignItems = "center";

imagesContainer.appendChild(generateImage());
imagesContainer.appendChild(nextButton);
imagesContainer.appendChild(prevButton);
sliderContainer.append(imagesContainer);

function changeImageSrc(index) {
  sliderContainer.childNodes[0].childNodes[0].src = imagesSrc[index];
}

document.addEventListener("DOMContentLoaded", () => changeImageSrc(0));

Conclusion

I believe that with this project, the concept of DOM has been introduced. DOM manipulation isn't a difficult concept however, it can easily get scary if not properly managed.