0

I am trying to make a slider for a list of products and I have placed a button on each side of the slider to slide the products. The problem I am facing is that it works fine when I press exactly at the buttons but when I press anywhere around it, it throws the error Uncaught TypeError: Cannot read property 'style' of null.

next = (target) => {
  target.parentElement.parentElement.previousElementSibling.style.transform = 'translateX(-44vw)';
  // next[0].style.display = 'none';
  // previous[0].style.display = 'inline-block';
}

previous = (target) => {
  target.parentElement.parentElement.previousElementSibling.style.transform = 'translateX(0vw)';
  // previous[0].style.display = 'none';
  // next[0].style.display = 'inline-block';
}
* {
  font-family: "Segoe UI";
}

.shop {
  background-color: rgb(255, 255, 255);
  overflow: hidden;
  position: relative;
  margin: 10px;
  margin-top: 0;
}

.product-display-area {
  width: 81.5vw;
  display: inline-block;
}

.shop_header {
  margin: 10px;
  margin-bottom: 0px;
  position: relative;
  padding: 10px;
  border-bottom: 1px solid rgb(229, 229, 229);
  background-color: rgb(255, 255, 255);
}

.shop_header h2 {
  display: inline-block;
  font-weight: 500;
  margin-left: 30px;
}

.shop_header p {
  margin-left: 30px;
}

.shop_header .clock {
  display: inline-block;
  margin-left: 30px;
}

.shop_header .clock img {
  position: relative;
  top: 6px;
  width: 24px;
}

.shop_header .clock #time_remaining {
  margin-left: 10px;
}

.shop_header button[type="button"] a {
  text-decoration: none;
  padding: 10px 15px;
  display: inline-block;
  font-size: 15px;
  font-weight: 700;
  background-color: rgb(40, 116, 240);
  color: rgb(255, 255, 255);
}

.shop_header button[type="button"] {
  border: none;
  position: absolute;
  right: 20px;
  top: 0px;
}

.shop_items {
  width: 130vw;
  transition: 1s;
}

.shop_items .items {
  display: inline-block;
  padding: 25px;
}

.shop_items .items img {
  display: block;
  margin: auto;
}

.shop_items .items .item_info {
  text-align: center;
  margin: auto;
}

.shop_items .items .item_info p {
  padding: 5px;
  color: rgb(56, 142, 60);
  font-size: 14px;
}

.shop_items .items .item_info p:first-of-type {
  color: rgb(0, 0, 0);
  font-weight: 500;
}

.shop_items .items .item_info p:last-of-type {
  color: rgb(151, 151, 151);
}

.item_carousel_left_arrow {
  position: absolute;
  top: 35%;
  padding: 50px 20px;
  border-top-right-radius: 5px;
  border-bottom-right-radius: 5px;
  border: 1px solid rgb(209, 211, 213);
  background-color: rgb(255, 255, 255);
  cursor: pointer;
}

.item_carousel_right_arrow {
  right: 0;
  position: absolute;
  top: 35%;
  padding: 50px 20px;
  border-top-left-radius: 5px;
  border-bottom-left-radius: 5px;
  border: 1px solid rgb(209, 211, 213);
  background-color: rgb(255, 255, 255);
  cursor: pointer;
}
<link rel="stylesheet" href="https://kit-pro.fontawesome.com/releases/v5.15.1/css/pro.min.css">
<div class="product-display-area">
  <div class="shop" id="best_of_electronics">
    <div class="shop_header">
      <h2>Best of Electronics</h2>
      <p>Devices and Accessories</p>
      <button type="button"><a href="#">VIEW ALL</a></button>
    </div>
    <div class="shop_items">
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/k4vmxzk0/cases-covers/back-cover/y/y/g/spigen-f23cs25961-original-imafnzhgzuty3gb6.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Best Brands</p>
            <p class="product_price">Shop Now</p>
            <p class="product_company">For All Phone Models</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kdhphu80/sports-action-camera/j/f/k/4000-air-4k-full-hd-wifi-30m-waterproof-sports-action-camera-original-imafue3ghmhtk39f.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Sports & Action Camera</p>
            <p class="product_price">From &#8377;4199</p>
            <p class="product_company">GoPro, SJCAM, DJI & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kbqu4cw0/speaker/soundbar/9/s/0/mt160dsb-motorola-original-imaftf6csukur9he.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Dolby Enabled</p>
            <p class="product_price">Up to 50% Off</p>
            <p class="product_company">Home Theaters</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/k6mibgw0/datacard/r/h/g/jiofi-jmr-541-original-imafpfhandhkptwc.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Data Cards</p>
            <p class="product_price">Upto 60% off</p>
            <p class="product_company">JioFi, Huawei & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/ja73ki80/webcam/pc-webcam/7/q/e/logitech-c310-original-imaeztzqny7jh7gh.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Webcams</p>
            <p class="product_price">From &#8377;499</p>
            <p class="product_company">Logitech, Quantum & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kb5eikw0/trimmer/z/d/n/0-5-10-mm-bt3101-15-stainless-steel-cordless-philips-original-imafsjquyq2hapug.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Trimmers & Hair Clippers</p>
            <p class="product_price">From &#8377;700</p>
            <p class="product_company">By Nova, Philips & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/k51cpe80/hearing-aid/e/e/s/ha50-behind-ear-beurer-original-imafnth6bue82ngc.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Best of Hearing Aids</p>
            <p class="product_price">From &#8377;499</p>
            <p class="product_company">Beurer & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kex5ci80/printer/k/n/z/hp-laserjet-pro-m1136-mfp-original-imafvhnbe2dg4vem.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Top 10 Printers</p>
            <p class="product_price">&#8377;2399</p>
            <p class="product_company">Print, Scan & copy</p>
          </div>
        </div>
      </a>
    </div>
    <div>
      <span class="item_carousel_left_arrow" id="arruw" onclick="previous(event.target)">
                        <i class="fas fa-arrow-left"></i>
                    </span>
      <span class="item_carousel_right_arrow" id="arruw" onclick="next(event.target)">
                        <i class="fas fa-arrow-right"></i>
                    </span>
    </div>
  </div>
</div>
  • You use `id="arruw"` twice, which is invalid. Please [validate your HTML](https://html5.validator.nu/). Inline event handlers like `onclick` are [not recommended](https://stackoverflow.com/q/11737873/4642212). They are an [obsolete, hard-to-maintain and unintuitive](https://stackoverflow.com/a/43459991/4642212) way of registering events. Always [use `addEventListener`](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Inline_event_handlers_—_dont_use_these) instead. – Sebastian Simon Dec 31 '20 at 16:56
  • The mistake comes from the fact that sometimes you click on the `` icon and sometimes you click on the `` button; therefore `event.target` and the long `parentElement` chain become inconsistent. Use [`.closest`](https://developer.mozilla.org/en-US/docs/Web/API/Element/closest) for consistent results. – Sebastian Simon Dec 31 '20 at 16:58

2 Answers2

2

You need to delegate and test what you clicked since you have two elements you can click, the button and the <i>

Also you have duplicate IDs which is not allowed (had you used them)

Also DRY (don't repeat yourself)

const shopItems = document.querySelector("#best_of_electronics .shop_items")

document.getElementById("nav").addEventListener("click", function(e) {
  let tgt = e.target;
  let possibleParent = tgt.closest("span")
  if (possibleParent) tgt = possibleParent; // we clicked the <i>
  shopItems.style.transform = tgt.id==="prev" ? 'translateX(-44vw)' : 'translateX(0vw)';
})
* {
  font-family: "Segoe UI";
}

.shop {
  background-color: rgb(255, 255, 255);
  overflow: hidden;
  position: relative;
  margin: 10px;
  margin-top: 0;
}

.product-display-area {
  width: 81.5vw;
  display: inline-block;
}

.shop_header {
  margin: 10px;
  margin-bottom: 0px;
  position: relative;
  padding: 10px;
  border-bottom: 1px solid rgb(229, 229, 229);
  background-color: rgb(255, 255, 255);
}

.shop_header h2 {
  display: inline-block;
  font-weight: 500;
  margin-left: 30px;
}

.shop_header p {
  margin-left: 30px;
}

.shop_header .clock {
  display: inline-block;
  margin-left: 30px;
}

.shop_header .clock img {
  position: relative;
  top: 6px;
  width: 24px;
}

.shop_header .clock #time_remaining {
  margin-left: 10px;
}

.shop_header button[type="button"] a {
  text-decoration: none;
  padding: 10px 15px;
  display: inline-block;
  font-size: 15px;
  font-weight: 700;
  background-color: rgb(40, 116, 240);
  color: rgb(255, 255, 255);
}

.shop_header button[type="button"] {
  border: none;
  position: absolute;
  right: 20px;
  top: 0px;
}

.shop_items {
  width: 130vw;
  transition: 1s;
}

.shop_items .items {
  display: inline-block;
  padding: 25px;
}

.shop_items .items img {
  display: block;
  margin: auto;
}

.shop_items .items .item_info {
  text-align: center;
  margin: auto;
}

.shop_items .items .item_info p {
  padding: 5px;
  color: rgb(56, 142, 60);
  font-size: 14px;
}

.shop_items .items .item_info p:first-of-type {
  color: rgb(0, 0, 0);
  font-weight: 500;
}

.shop_items .items .item_info p:last-of-type {
  color: rgb(151, 151, 151);
}

.item_carousel_left_arrow {
  position: absolute;
  top: 35%;
  padding: 50px 20px;
  border-top-right-radius: 5px;
  border-bottom-right-radius: 5px;
  border: 1px solid rgb(209, 211, 213);
  background-color: rgb(255, 255, 255);
  cursor: pointer;
}

.item_carousel_right_arrow {
  right: 0;
  position: absolute;
  top: 35%;
  padding: 50px 20px;
  border-top-left-radius: 5px;
  border-bottom-left-radius: 5px;
  border: 1px solid rgb(209, 211, 213);
  background-color: rgb(255, 255, 255);
  cursor: pointer;
}
<link rel="stylesheet" href="https://kit-pro.fontawesome.com/releases/v5.15.1/css/pro.min.css">
<div class="product-display-area">
  <div class="shop" id="best_of_electronics">
    <div class="shop_header">
      <h2>Best of Electronics</h2>
      <p>Devices and Accessories</p>
      <button type="button"><a href="#">VIEW ALL</a></button>
    </div>
    <div class="shop_items">
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/k4vmxzk0/cases-covers/back-cover/y/y/g/spigen-f23cs25961-original-imafnzhgzuty3gb6.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Best Brands</p>
            <p class="product_price">Shop Now</p>
            <p class="product_company">For All Phone Models</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kdhphu80/sports-action-camera/j/f/k/4000-air-4k-full-hd-wifi-30m-waterproof-sports-action-camera-original-imafue3ghmhtk39f.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Sports & Action Camera</p>
            <p class="product_price">From &#8377;4199</p>
            <p class="product_company">GoPro, SJCAM, DJI & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kbqu4cw0/speaker/soundbar/9/s/0/mt160dsb-motorola-original-imaftf6csukur9he.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Dolby Enabled</p>
            <p class="product_price">Up to 50% Off</p>
            <p class="product_company">Home Theaters</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/k6mibgw0/datacard/r/h/g/jiofi-jmr-541-original-imafpfhandhkptwc.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Data Cards</p>
            <p class="product_price">Upto 60% off</p>
            <p class="product_company">JioFi, Huawei & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/ja73ki80/webcam/pc-webcam/7/q/e/logitech-c310-original-imaeztzqny7jh7gh.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Webcams</p>
            <p class="product_price">From &#8377;499</p>
            <p class="product_company">Logitech, Quantum & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kb5eikw0/trimmer/z/d/n/0-5-10-mm-bt3101-15-stainless-steel-cordless-philips-original-imafsjquyq2hapug.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Trimmers & Hair Clippers</p>
            <p class="product_price">From &#8377;700</p>
            <p class="product_company">By Nova, Philips & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/k51cpe80/hearing-aid/e/e/s/ha50-behind-ear-beurer-original-imafnth6bue82ngc.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Best of Hearing Aids</p>
            <p class="product_price">From &#8377;499</p>
            <p class="product_company">Beurer & more</p>
          </div>
        </div>
      </a>
      <a href="#">
        <div class="items">
          <div>
            <img src="https://rukminim1.flixcart.com/image/150/150/kex5ci80/printer/k/n/z/hp-laserjet-pro-m1136-mfp-original-imafvhnbe2dg4vem.jpeg?q=70">
          </div>
          <div class="item_info">
            <p class="product_name">Top 10 Printers</p>
            <p class="product_price">&#8377;2399</p>
            <p class="product_company">Print, Scan & copy</p>
          </div>
        </div>
      </a>
    </div>
    <div id="nav">
      <span class="item_carousel_left_arrow arrow" id="prev">
                        <i class="fas fa-arrow-left"></i>
                    </span>
      <span class="item_carousel_right_arrow arrow" id="next">
                        <i class="fas fa-arrow-right"></i>
                    </span>
    </div>
  </div>
</div>

If you must have inline handlers, you can pass (this) - it is the same as event.target and use the saved div

 <span class="item_carousel_left_arrow" id="prev" onclick="nav(this)">
   <i class="fas fa-arrow-left"></i>
 </span>
 <span class="item_carousel_right_arrow" id="next" onclick="nav(this)">
   <i class="fas fa-arrow-right"></i>
 </span>

using

 const shopItems = document.querySelector("#best_of_electronics .shop_items")
 function nav(span) {
   shopItems.style.transform = span.id==="prev" ? 'translateX(-44vw)' : 'translateX(0vw)';
 }
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • what does the 'e' refers to that you passed as an argument in the parameter? – Noamaan Mulla Dec 31 '20 at 17:49
  • 1
    That is the event – mplungjan Dec 31 '20 at 17:50
  • The thing is I have a multiple of these sliders so will it work if I make an array of shopItems and put all the elements in it? – Noamaan Mulla Jan 01 '21 at 13:05
  • If you have several and each has a set of prev/next, then you can add the ID of the shopItem to a data-attribute. Let me know if I should update my code for that – mplungjan Jan 01 '21 at 13:11
  • Sure that would be really helpful – Noamaan Mulla Jan 01 '21 at 13:20
  • Sorry, I actually cannot make that work since you use position absolute, so the navigation spans are in one place. If you want to have navigation for each shopt item carousel, you need to make the carousel position: relative and have a set of spans inside a container for the carousel. That is too much rewriting for me to undertake since it will change your layout – mplungjan Jan 01 '21 at 14:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226705/discussion-between-noamaan-mulla-and-mplungjan). – Noamaan Mulla Jan 01 '21 at 17:34
0

Simply change next and previous function to these:

let next = () => {
    document.querySelector(".shop_items").style.transform = 'translateX(-44vw)';
}

let previous = () => {
    document.querySelector(".shop_items").style.transform = 'translateX(0vw)';
}

Or even you can change the onclick parameter and use only one function for both next and previous as this:

let nextPrev = (value) => {
    document.querySelector(".shop_items").style.transform = 'translateX(' + value + ')';
}

<div>
    <span class="item_carousel_left_arrow" id="arruw" onclick="nextPrev('0vw')">
        <i class="fas fa-arrow-left"></i>
    </span>
    <span class="item_carousel_right_arrow" id="arruw" onclick="nextPrev('-44vw')">
        <i class="fas fa-arrow-right"></i>
    </span>
</div>

Vahid
  • 655
  • 4
  • 11