0

How can I check an element if it is exists in the parent element? I'm implementing an increase/decrease button for product quantity in my project. I can increase and decrease the quantity when the user clicks those buttons. I have a _parentElement which I render an element and data and the error message (this will only render when there's an error). I've attached a click event to that _parentElement (this is visible in the DOM) and do event delegation.

This error will only log when the error message is rendered in the _parentElement and when I click on the _parentElement.

Error: Cannot read properties of null (reading 'innerHTML') at DetailView._handlerQuantity

This what I did:

View.js

import icons from 'url:../../icons/icons.svg';

export default class View {
  _data;
  
  renderError(message = this._errorMessage) {
    const html = /*html*/ `
      <div class="flex flex-col items-center justify-center gap-4 min-h-[inherit]">
        <svg class="h-6 w-6 sm:h-10 sm:w-10 fill-red-600">
          <use xlink:href="${icons}#icon-warning"></use>
        </svg>
        <span class="text-xl text-neutral-600 font-medium sm:text-xl xs:text-lg">${message}</span>
      </div>
    `;

    const markup = this._parseStringtoHTML(html);
    this._parentElement.innerHTML = '';
    this._parentElement.insertAdjacentElement('afterbegin', markup.body.firstElementChild);
  }
}

DetailView.js

class DetailView extends View {
  _parentElement = document.querySelector(".product__details");
  _errorMessage = "We could'nt find the product. Please try another one!";

  constructor() {
    super();
    this._addHandlerProductQuanity();
  }

  _handlerQuantity(e) {
    const increase = e.target.closest(".btn__control--add");
    const decrease = e.target.closest(".btn__control--minus");
    let quantity = document.querySelector(".product__quantity");
    const currentValue = Number(quantity.innerHTML) || 0;

    if (increase)
      Number(quantity.innerHTML) < this._data.stocks
        ? (quantity.innerHTML = currentValue + 1)
        : 1;

    if (decrease)
      Number(quantity.innerHTML > 1)
        ? (quantity.innerHTML = currentValue - 1)
        : 1;
  }

  _addHandlerProductQuanity() {
    this._parentElement.addEventListener(
      "click",
      this._handlerQuantity.bind(this)
    );
  }
}

HTML:

<main class="main min-h-[calc(100vh-5rem)] sm:min-h-[calc(100vh-8rem)]">
  <section class="product__details min-h-[inherit]">
    <!-- PRODUCTS DETAILS WILL GO HERE... -->
  </section>
</main>
J.Wujeck
  • 280
  • 4
  • 16

1 Answers1

1

Instead of this:

const currentValue = Number(quantity.innerHTML) || 0;

You can do this:

const currentValue = Number(quantity?.innerHTML ?? 0);

The ?. will basically check if the object to the left exists (in this case, quantity) before trying to get the property on the right (innerHTML). If it doesn't exist, then it'll returned undefined. The ?? will then kick in and return 0 instead.

That solves getting the current value.

But then, you're trying to set a value to a thing that might not exist. That's bad news. There are a couple of ways to go about it, but probably the best would just be to check if it is falsey, and if it is, go ahead and create it:

if (!quantity) {
  // code to create quantity and apparent it to its parent here
  // don't forget to set its default value to 0.
  // and assign it to quantity
}

Or, better yet:

const quantity = document.querySelector('.product__quantity') ?? createQuantity(); 
// createQuantity() being the function that creates and returns the element.

If you put that block before the const currentValue line, you don't have to do the stuff to handle null and can just do:

const currentValue = Number(quantity.innerHTML);

Also, I'm not sure what you want this bit to do:

Number(quantity.innerHTML) < this._data.stocks
    ? (quantity.innerHTML = currentValue + 1)
    : 1;

But how it is written, that last 1 just gets thrown away and does absolutely nothing, so, assuming you just want to increment the quantity if it is less then current stocks, you should rewrite it to be:

currentValue < this._data.stocks && (quantity.innerHTML = currentValue + 1);

(Also, only less than, not less than or equal to?)

Side note: You should probably use .textContent or .innerText instead of .innerHTML for getting the quantity, since you don't want any HTML that might be hanging out in there, only the text value. Even better, don't parse the text at all and just store the value as a property which you write out when it changes:

 // initialize
 quantity.value = 0;

 // increment
 quantity.value++;
 quantity.innerText = quantity.value;

To create the quantity element, you can do something like this:

function createQuantity() {
  // Use whatever element it should be
  const quantity = document.createElement('span');

  quantity.classList.add('product__quantity');

  // You'll probably need to tweak this to get it in the right spot
  __parentElement.appendChild(quantity);

  return quantity;
}
samanime
  • 25,408
  • 15
  • 90
  • 139
  • Awesome! Thank you for this. But what do you mean by these comments? // code to create quantity and apparent it to its parent here // don't forget to set its default value to 0. // and assign it to quantity – J.Wujeck Apr 06 '22 at 17:16
  • Do you mean if the quantity text is falsy then I will create an element quantity text? – J.Wujeck Apr 06 '22 at 17:18
  • No, if the quantity element is falsy. That error message implies that the quantity element doesn't exist, at least when you're trying to use it. – samanime Apr 06 '22 at 18:08
  • if (!quantity) { quantity.value = 0; } – J.Wujeck Apr 07 '22 at 02:05
  • This will I gonna do? – J.Wujeck Apr 07 '22 at 02:06
  • `if (!quantity)` means quantity doesn't exist. You have to create it first. You can't set a value to something that doesn't exist. You'd need to do use `document.createElement()` to create an element, set its class, and append it to the right spot. – samanime Apr 07 '22 at 07:06
  • Thanks! Can you help me with this one? https://stackoverflow.com/questions/71778222/filter-product-price-using-input-range-and-render-in-the-dom – J.Wujeck Apr 07 '22 at 07:52