Mastering JavaScript: 30 Hands-on Projects for Beginners (Project Series 3/30)

Mastering JavaScript: 30 Hands-on Projects for Beginners (Project Series 3/30)

Understanding JavaScript fundamentals by building a Reviews Slider for a Website

Introduction

Welcome to the third article in the project series "Mastering JavaScript: 30 Hands-on Projects." In the 2nd article, we built a Simple Counter Application that allows a user to increment, decrement, and reset the counter value and updates the displayed value and its colour based on the current value.

The article series aims to build your mastery of JavaScript by building 30 simple projects. After building the projects, you'll feel confident enough to pick up any JavaScript framework.

Today, we'll be building Project 3 of the Project Series and we'll be working on a Review Slider for a Website.

Project 3: Reviews Slider

Working Project:

The goal of this project is to allow a user to navigate through the reviews and see different people's information (like their name, job and their review itself). The interesting part is that some of the JavaScript concepts that were applied in the last project will also be used here, which means we are building on what you already know, which is a great way to learn Javascript.

New JavaScript concepts that'll be applied:

  1. Working with Local Data: Arrays and Objects

  2. DOM Manipulation

  3. Event Listeners

  4. Conditional Statements

  5. Math.random()

  6. Math.floor()

  7. DOMContentLoaded

If you're not very conversant with these concepts, I've added links to tutorials in the resources section of the article to bring you up to speed. You can read about them before you start this project

I have also provided the HTML and CSS codes which you can copy to your local machine so we can only focus on explaining the JavaScript logic.

HTML Codes:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Starter</title>
    <!-- font-awesome -->
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
    />

    <!-- styles -->
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <main>
      <section class="container">
        <!--title-->
        <div class="title">
          <h2>Our Reviews</h2>
          <div class="underline"></div>
        </div>
        <!--review-->
        <article class="review">
          <div class="img-container">
            <img src="./person-1.jpeg" alt="reviewer" id="person-img" />
          </div>
          <h4 id="author">Ngozi Okoli</h4>
          <p id="job">ux designer</p>
          <p id="info">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugiat
            nobis illo enim quidem facilis officiis ratione, corrupti incidunt
            quaerat temporibus.
          </p>
          <!--prev next buttons-->
          <div class="button-container">
            <button class="prev-btn">
              <i class="fas fa-chevron-left"></i>
            </button>
            <button class="next-btn">
              <i class="fas fa-chevron-right"></i>
            </button>
          </div>
          <!--random button-->
          <button class="random-btn">Random Review</button>
        </article>
      </section>
    </main>
    <script src="app.js"></script>
  </body>
</html>

CSS Codes:

/*
=============== 
Fonts
===============
*/
@import url("https://fonts.googleapis.com/css?family=Open+Sans|Roboto:400,700&display=swap");

/*
=============== 
Variables
===============
*/

:root {
  /* dark shades of primary color*/
  --clr-primary-1: hsl(205, 86%, 17%);
  --clr-primary-2: hsl(205, 77%, 27%);
  --clr-primary-3: hsl(205, 72%, 37%);
  --clr-primary-4: hsl(205, 63%, 48%);
  /* primary/main color */
  --clr-primary-5: hsl(205, 78%, 60%);
  /* lighter shades of primary color */
  --clr-primary-6: hsl(205, 89%, 70%);
  --clr-primary-7: hsl(205, 90%, 76%);
  --clr-primary-8: hsl(205, 86%, 81%);
  --clr-primary-9: hsl(205, 90%, 88%);
  --clr-primary-10: hsl(205, 100%, 96%);
  /* darkest grey - used for headings */
  --clr-grey-1: hsl(209, 61%, 16%);
  --clr-grey-2: hsl(211, 39%, 23%);
  --clr-grey-3: hsl(209, 34%, 30%);
  --clr-grey-4: hsl(209, 28%, 39%);
  /* grey used for paragraphs */
  --clr-grey-5: hsl(210, 22%, 49%);
  --clr-grey-6: hsl(209, 23%, 60%);
  --clr-grey-7: hsl(211, 27%, 70%);
  --clr-grey-8: hsl(210, 31%, 80%);
  --clr-grey-9: hsl(212, 33%, 89%);
  --clr-grey-10: hsl(210, 36%, 96%);
  --clr-white: #fff;
  --clr-red-dark: hsl(360, 67%, 44%);
  --clr-red-light: hsl(360, 71%, 66%);
  --clr-green-dark: hsl(125, 67%, 44%);
  --clr-green-light: hsl(125, 71%, 66%);
  --clr-black: #222;
  --ff-primary: "Roboto", sans-serif;
  --ff-secondary: "Open Sans", sans-serif;
  --transition: all 0.3s linear;
  --spacing: 0.1rem;
  --radius: 0.25rem;
  --light-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
  --dark-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
  --max-width: 1170px;
  --fixed-width: 620px;
}
/*
=============== 
Global Styles
===============
*/

*,
::after,
::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  font-family: var(--ff-secondary);
  background: var(--clr-grey-10);
  color: var(--clr-grey-1);
  line-height: 1.5;
  font-size: 0.875rem;
}
ul {
  list-style-type: none;
}
a {
  text-decoration: none;
}
h1,
h2,
h3,
h4 {
  letter-spacing: var(--spacing);
  text-transform: capitalize;
  line-height: 1.25;
  margin-bottom: 0.75rem;
  font-family: var(--ff-primary);
}
h1 {
  font-size: 3rem;
}
h2 {
  font-size: 2rem;
}
h3 {
  font-size: 1.25rem;
}
h4 {
  font-size: 0.875rem;
}
p {
  margin-bottom: 1.25rem;
  color: var(--clr-grey-5);
}
@media screen and (min-width: 800px) {
  h1 {
    font-size: 4rem;
  }
  h2 {
    font-size: 2.5rem;
  }
  h3 {
    font-size: 1.75rem;
  }
  h4 {
    font-size: 1rem;
  }
  body {
    font-size: 1rem;
  }
  h1,
  h2,
  h3,
  h4 {
    line-height: 1;
  }
}
/*  global classes */

/* section */
.section {
  padding: 5rem 0;
}

.section-center {
  width: 90vw;
  margin: 0 auto;
  max-width: 1170px;
}
@media screen and (min-width: 992px) {
  .section-center {
    width: 95vw;
  }
}
main {
  min-height: 100vh;
  display: grid;
  place-items: center;
}

/*
=============== 
Reviews
===============
*/
main {
  min-height: 100vh;
  display: grid;
  place-items: center;
}
.title {
  text-align: center;
  margin-bottom: 4rem;
}
.underline {
  height: 0.25rem;
  width: 5rem;
  background: var(--clr-primary-5);
  margin-left: auto;
  margin-right: auto;
}
.container {
  width: 80vw;
  max-width: var(--fixed-width);
}
.review {
  background: var(--clr-white);
  padding: 1.5rem 2rem;
  border-radius: var(--radius);
  box-shadow: var(--light-shadow);
  transition: var(--transition);
  text-align: center;
}
.review:hover {
  box-shadow: var(--dark-shadow);
}
.img-container {
  position: relative;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  margin: 0 auto;
  margin-bottom: 1.5rem;
}
#person-img {
  width: 100%;
  display: block;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  position: relative;
}
.img-container::after {
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  content: "\f10e";
  position: absolute;
  top: 0;
  left: 0;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  transform: translateY(25%);
  background: var(--clr-primary-5);
  color: var(--clr-white);
}
.img-container::before {
  content: "";
  width: 100%;
  height: 100%;
  background: var(--clr-primary-5);
  position: absolute;
  top: -0.25rem;
  right: -0.5rem;
  border-radius: 50%;
}
#author {
  margin-bottom: 0.25rem;
}
#job {
  margin-bottom: 0.5rem;
  text-transform: uppercase;
  color: var(--clr-primary-5);
  font-size: 0.85rem;
}
#info {
  margin-bottom: 0.75rem;
}
.prev-btn,
.next-btn {
  color: var(--clr-primary-7);
  font-size: 1.25rem;
  background: transparent;
  border-color: transparent;
  margin: 0 0.5rem;
  transition: var(--transition);
  cursor: pointer;
}
.prev-btn:hover,
.next-btn:hover {
  color: var(--clr-primary-5);
}
.random-btn {
  margin-top: 0.5rem;
  background: var(--clr-primary-10);
  color: var(--clr-primary-5);
  padding: 0.25rem 0.5rem;
  text-transform: capitalize;
  border-radius: var(--radius);
  transition: var(--transition);
  border-color: var(--clr-primary-5);
  cursor: pointer;
}
.random-btn:hover {
  background: var(--clr-primary-5);
  color: var(--clr-primary-1);
}

Remember that the Javascript logic we are about to write should be written in app.js folder of the project.

The JavaScript Logic:

We begin this project by providing the local data (or user reviews) that we'll be working with. The reviews are stored in an array called "reviews," which contains objects representing each review. Each object has properties such as the id, name, job title, image URL, and text of the review.

const reviews = [
  {
    id: 1,
    name: "Janelle Okoro",
    job: "web developer",
    img:
    "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
    text:
      "I'm baby meggings twee health goth +1. Bicycle rights tumeric chartreuse before they sold out chambray pop-up. Shaman humblebrag pickled coloring book salvia hoodie, cold-pressed four dollar toast everyday carry",
  },
  {
    id: 2,
    name: "Shannon Bakare",
    job: "web designer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
    text:
      "Helvetica artisan kinfolk thundercats lumbersexual blue bottle. Disrupt glossier gastropub deep v vice franzen hell of brooklyn twee enamel pin fashion axe.photo booth jean shorts artisan narwhal.",
  },
  {
    id: 3,
    name: "Peter Hassan",
    job: "intern",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
    text:
      "Sriracha literally flexitarian irony, vape marfa unicorn. Glossier tattooed 8-bit, fixie waistcoat offal activated charcoal slow-carb marfa hell of pabst raclette post-ironic jianbing swag.",
  },
  {
    id: 4,
    name: "Jake Akpan",
    job: "the boss",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883423/person-4_t9nxjt.jpg",
    text:
      "Edison bulb put a bird on it humblebrag, marfa pok pok heirloom fashion axe cray stumptown venmo actually seitan. VHS farm-to-table schlitz, edison bulb pop-up 3 wolf moon tote bag street art shabby chic. ",
  },
];

Next, we need to make references to elements in the HTML document, such as an image and text elements to display the person's information. These references are stored in variables such as img, author, job and info. We also make references to buttons for next, previous and random review in the HTML document and store them in variables prevBtn, nextBtn, and randomBtn respectively.

 // local  data
const reviews = [
  {
    id: 1,
    name: "Janelle Okoro",
    job: "web developer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
    text:
      "I'm baby meggings twee health goth +1. Bicycle rights tumeric chartreuse before they sold out chambray pop-up. Shaman humblebrag pickled coloring book salvia hoodie, cold-pressed four dollar toast everyday carry",
  },
  {
    id: 2,
    name: "Shannon Bakare",
    job: "web designer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
    text:
      "Helvetica artisan kinfolk thundercats lumbersexual blue bottle. Disrupt glossier gastropub deep v vice franzen hell of brooklyn twee enamel pin fashion axe.photo booth jean shorts artisan narwhal.",
  },
  {
    id: 3,
    name: "Peter Hassan",
    job: "intern",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
    text:
      "Sriracha literally flexitarian irony, vape marfa unicorn. Glossier tattooed 8-bit, fixie waistcoat offal activated charcoal slow-carb marfa hell of pabst raclette post-ironic jianbing swag.",
  },
  {
    id: 4,
    name: "Jake Akpan",
    job: "the boss",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883423/person-4_t9nxjt.jpg",
    text:
      "Edison bulb put a bird on it humblebrag, marfa pok pok heirloom fashion axe cray stumptown venmo actually seitan. VHS farm-to-table schlitz, edison bulb pop-up 3 wolf moon tote bag street art shabby chic. ",
  },
];
// grab hold of the DOM objects, so we can manipulate it
const img = document.getElementById('person-img');
const author = document.getElementById('author');
const job = document.getElementById('job');
const info = document.getElementById('info');

const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const randomBtn = document.querySelector('.random-btn');

Now, we use currentItem variable is defined to keep track of which review is currently being displayed.

// local texts data
const reviews = [
  //object data minimised
];

// grab hold of the DOM objects, so we can manipulate it
const img = document.getElementById('person-img');
const author = document.getElementById('author');
const job = document.getElementById('job');
const info = document.getElementById('info');

const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const randomBtn = document.querySelector('.random-btn');

//set a initial review item
let currentItem = 0;

Next, we write a function showPerson() that will be used to update the current review when the previous, next, or random button is clicked. The currentItem variable keeps track of which review is currently being displayed.

const reviews = [
  {
    id: 1,
    name: "Janelle Okoro",
    job: "web developer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
    text:
      "I'm baby meggings twee health goth +1. Bicycle rights tumeric chartreuse before they sold out chambray pop-up. Shaman humblebrag pickled coloring book salvia hoodie, cold-pressed four dollar toast everyday carry",
  },
  {
    id: 2,
    name: "Shannon Bakare",
    job: "web designer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
    text:
      "Helvetica artisan kinfolk thundercats lumbersexual blue bottle. Disrupt glossier gastropub deep v vice franzen hell of brooklyn twee enamel pin fashion axe.photo booth jean shorts artisan narwhal.",
  },
  {
    id: 3,
    name: "Peter Hassan",
    job: "intern",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
    text:
      "Sriracha literally flexitarian irony, vape marfa unicorn. Glossier tattooed 8-bit, fixie waistcoat offal activated charcoal slow-carb marfa hell of pabst raclette post-ironic jianbing swag.",
  },
  {
    id: 4,
    name: "Jake Akpan",
    job: "the boss",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883423/person-4_t9nxjt.jpg",
    text:
      "Edison bulb put a bird on it humblebrag, marfa pok pok heirloom fashion axe cray stumptown venmo actually seitan. VHS farm-to-table schlitz, edison bulb pop-up 3 wolf moon tote bag street art shabby chic. ",
  },
];
// grab hold of the DOM objects, so we can manipulate it
const img = document.getElementById('person-img');
const author = document.getElementById('author');
const job = document.getElementById('job');
const info = document.getElementById('info');

const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const randomBtn = document.querySelector('.random-btn');

//set a initial review item
let currentItem = 0;

//show person based on item
const showPerson = () => {
  const review = reviews[currentItem];
  img.src = review.img;
  author.textContent = review.name;
  job.textContent = review.job;
  info.textContent = review.text;
}

Observe the code.

The showPerson function is called to display the current review by setting the src attribute of the image element to the "img" property of the current review object, the textContent of the author element to the "name" property, the textContent of the job element to the "job" property, and the textContent of the info element to the "text" property.

Furthermore, we have to add an event listener to wait for the DOMContentLoaded event, which is triggered when the entire HTML document has been loaded and parsed. Once the event is triggered, the showPerson function is called, which displays the first review.

const reviews = [
  {
    id: 1,
    name: "Janelle Okoro",
    job: "web developer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
    text:
      "I'm baby meggings twee health goth +1. Bicycle rights tumeric chartreuse before they sold out chambray pop-up. Shaman humblebrag pickled coloring book salvia hoodie, cold-pressed four dollar toast everyday carry",
  },
  {
    id: 2,
    name: "Shannon Bakare",
    job: "web designer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
    text:
      "Helvetica artisan kinfolk thundercats lumbersexual blue bottle. Disrupt glossier gastropub deep v vice franzen hell of brooklyn twee enamel pin fashion axe.photo booth jean shorts artisan narwhal.",
  },
  {
    id: 3,
    name: "Peter Hassan",
    job: "intern",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
    text:
      "Sriracha literally flexitarian irony, vape marfa unicorn. Glossier tattooed 8-bit, fixie waistcoat offal activated charcoal slow-carb marfa hell of pabst raclette post-ironic jianbing swag.",
  },
  {
    id: 4,
    name: "Jake Akpan",
    job: "the boss",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883423/person-4_t9nxjt.jpg",
    text:
      "Edison bulb put a bird on it humblebrag, marfa pok pok heirloom fashion axe cray stumptown venmo actually seitan. VHS farm-to-table schlitz, edison bulb pop-up 3 wolf moon tote bag street art shabby chic. ",
  },
];


// grab hold of the DOM objects, so we can manipulate it
const img = document.getElementById('person-img');
const author = document.getElementById('author');
const job = document.getElementById('job');
const info = document.getElementById('info');

const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const randomBtn = document.querySelector('.random-btn');

//set a initial review item
let currentItem = 0;

//show person based on item
const showPerson = () => {
  const review = reviews[currentItem];
  img.src = review.img;
  author.textContent = review.name;
  job.textContent = review.job;
  info.textContent = review.text;
}

//once the document loads, display that review (load initial review item)
window.addEventListener('DOMContentLoaded', () => {
  showPerson();
});

We have to set up an event listener for the "click" event on the next button. When the button is clicked, the event listener will be triggered, and the following code will be executed:

//next review button
nextBtn.addEventListener('click', () => {
  currentItem++;
  if(currentItem > reviews.length -1){
    currentItem = 0;
  }
  showPerson();
})

When the next button is clicked, the currentItem variable is incremented by 1. This moves the current review to the next one in the reviews array. The code then checks if the currentItem is greater than the length of the reviews array. If it is, it means that we have reached the end of the reviews array, so the currentItem is set to 0, which will display the first review again. Finally, the showReviewer function is called to display the next review. This allows the user to navigate through the reviews by clicking the next button.

const reviews = [
  {
    id: 1,
    name: "Janelle Okoro",
    job: "web developer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
    text:
      "I'm baby meggings twee health goth +1. Bicycle rights tumeric chartreuse before they sold out chambray pop-up. Shaman humblebrag pickled coloring book salvia hoodie, cold-pressed four dollar toast everyday carry",
  },
  {
    id: 2,
    name: "Shannon Bakare",
    job: "web designer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
    text:
      "Helvetica artisan kinfolk thundercats lumbersexual blue bottle. Disrupt glossier gastropub deep v vice franzen hell of brooklyn twee enamel pin fashion axe.photo booth jean shorts artisan narwhal.",
  },
  {
    id: 3,
    name: "Peter Hassan",
    job: "intern",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
    text:
      "Sriracha literally flexitarian irony, vape marfa unicorn. Glossier tattooed 8-bit, fixie waistcoat offal activated charcoal slow-carb marfa hell of pabst raclette post-ironic jianbing swag.",
  },
  {
    id: 4,
    name: "Jake Akpan",
    job: "the boss",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883423/person-4_t9nxjt.jpg",
    text:
      "Edison bulb put a bird on it humblebrag, marfa pok pok heirloom fashion axe cray stumptown venmo actually seitan. VHS farm-to-table schlitz, edison bulb pop-up 3 wolf moon tote bag street art shabby chic. ",
  },
];


// grab hold of the DOM objects, so we can manipulate it
const img = document.getElementById('person-img');
const author = document.getElementById('author');
const job = document.getElementById('job');
const info = document.getElementById('info');

const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const randomBtn = document.querySelector('.random-btn');

//set a initial review item
let currentItem = 0;

//show person based on item
const showPerson = () => {
  const review = reviews[currentItem];
  img.src = review.img;
  author.textContent = review.name;
  job.textContent = review.job;
  info.textContent = review.text;
}

//once the document loads, display that review (load initial review item)
window.addEventListener('DOMContentLoaded', () => {
  showReviewer();
});

//next review button
nextBtn.addEventListener('click', () => {
  currentItem++;
  if(currentItem > reviews.length -1){
    currentItem = 0;
  }
  showPerson();
})

The same logic also applies to our previous button.

When the previous button is clicked, the currentItem variable is decremented by 1. This moves the current review to the previous one in the reviews array. The code then checks if the currentItem is less than 0. If it is, it means that we have reached the beginning of the reviews array, so the currentItem is set to the last item in the reviews array which will display the last review again. Finally, the showPerson function is called to display the previous review. This allows the user to navigate through the reviews by clicking the prev button.

Finally, we set up an event listener for the "click" event on the random button. When the button is clicked, the event listener will be triggered, and the following code will be executed:

currentItem = Math.floor(Math.random() * reviews.length);
  showPerson();

The Math.floor(Math.random() * reviews.length) calculates a random number between 0 and the length of the reviews array, using JavaScript's Math object. The Math.random() method returns a random number between 0 (inclusive) and 1 (exclusive). By multiplying that by the length of the reviews array, we get a random number between 0 and the last index of the reviews array, but as a decimal. Using Math.floor() rounds that number down to the nearest whole number.

This random number will be the new value assigned to the currentItem variable, which will be used to display a random review from the reviews array. Finally, the showPerson function is called to display the randomly selected review. This allows the user to view a random review by clicking the random button.

This is our final code:

 // local data
const reviews = [
  {
    id: 1,
    name: "Janelle Okoro",
    job: "web developer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
    text:
      "I'm baby meggings twee health goth +1. Bicycle rights tumeric chartreuse before they sold out chambray pop-up. Shaman humblebrag pickled coloring book salvia hoodie, cold-pressed four dollar toast everyday carry",
  },
  {
    id: 2,
    name: "Shannon Bakare",
    job: "web designer",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
    text:
      "Helvetica artisan kinfolk thundercats lumbersexual blue bottle. Disrupt glossier gastropub deep v vice franzen hell of brooklyn twee enamel pin fashion axe.photo booth jean shorts artisan narwhal.",
  },
  {
    id: 3,
    name: "Peter Hassan",
    job: "intern",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
    text:
      "Sriracha literally flexitarian irony, vape marfa unicorn. Glossier tattooed 8-bit, fixie waistcoat offal activated charcoal slow-carb marfa hell of pabst raclette post-ironic jianbing swag.",
  },
  {
    id: 4,
    name: "Jake Akpan",
    job: "the boss",
    img:
      "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883423/person-4_t9nxjt.jpg",
    text:
      "Edison bulb put a bird on it humblebrag, marfa pok pok heirloom fashion axe cray stumptown venmo actually seitan. VHS farm-to-table schlitz, edison bulb pop-up 3 wolf moon tote bag street art shabby chic. ",
  },
];


// grab hold of the DOM objects, so we can manipulate it
const img = document.getElementById('person-img');
const author = document.getElementById('author');
const job = document.getElementById('job');
const info = document.getElementById('info');

const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const randomBtn = document.querySelector('.random-btn');

//set a initial review item
let currentItem = 0;

//show person based on item
const showPerson = () => {
  const review = reviews[currentItem];
  img.src = review.img;
  author.textContent = review.name;
  job.textContent = review.job;
  info.textContent = review.text;
}

//once the document loads, display that review (load initial review item)
window.addEventListener('DOMContentLoaded', () => {
  showPerson();
});

//next review button
nextBtn.addEventListener('click', () => {
  currentItem++;
  if(currentItem > reviews.length -1){
    currentItem = 0;
  }
  showPerson();
})

//prev review button
prevBtn.addEventListener('click', () => {
  currentItem--;
  if(currentItem < 0){
    currentItem = reviews.length-1;
  }
  showPerson();
})

//random review button
randomBtn.addEventListener('click', () => {
  currentItem = Math.floor(Math.random() * reviews.length);
  showPerson();
})

And we're done!

Short and sweet, init?

Conclusion

In this article, we created a reviews slider for a website using JavaScript. The application allows the user to view the different user reviews by clicking the next and previous buttons. This project is a basic example of how to create a dynamic and interactive feature with JavaScript.

This project can be a good starting point for more advanced projects and will help you build a solid foundation in JavaScript. With the knowledge gained from this article, you can build more complex projects and take your skills to the next level.

Watch out for Project 3/30 soon. Thanks for reading!

Resources

  1. Arrays: The reviews are stored in an array of objects. To learn more about arrays in JavaScript, you can refer to this tutorial: w3schools.com/js/js_arrays.asp

  2. Objects: Each review is an object with properties such as name, job, image, and text. To learn more about objects in JavaScript, you can refer to this tutorial: w3schools.com/js/js_objects.asp

  3. DOM Manipulation: The code uses JavaScript to manipulate the DOM elements and update the review information displayed on the page. To learn more about DOM manipulation, you can refer to this tutorial: w3schools.com/js/js_htmldom.asp

  4. Event Listeners: The code uses event listeners to listen for clicks on the next, prev, and random buttons, and updates the review information accordingly. To learn more about event listeners, you can refer to this tutorial: w3schools.com/js/js_events.asp

  5. Conditional Statements: The code uses if-else statements to check if the current review is the first or last item in the reviews array, and updates the currentItem variable accordingly. To learn more about conditional statements in JavaScript, you can refer to this tutorial: w3schools.com/js/js_if_else.asp

  6. Math.random(): The code uses Math.random() to generate a random number for the currentItem variable when the random button is clicked. To learn more about Math.random() in JavaScript, you can refer to this tutorial: w3schools.com/js/js_random.asp

  7. Math.floor(): The code uses Math.floor() to round the random number generated by Math.random() to the nearest integer. To learn more about Math.floor() in JavaScript, you can refer to this tutorial: w3schools.com/js/js_math.asp

  8. DOMContentLoaded: The code uses DOMContentLoaded event to show the reviewer when the DOM is loaded. To learn more about DOMContentLoaded, you can refer to this tutorial: developer.mozilla.org/en-US/docs/Web/API/Do..

Please note that some of the tutorials may not cover all the concepts I listed, but it is a good place to start.

Credits

Special credit goes to John Smilger for using his projects in this article series.