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 >
<svg >
<use xlink:href="${icons}#icon-warning"></use>
</svg>
<span >${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 >
<section >
<!-- PRODUCTS DETAILS WILL GO HERE... -->
</section>
</main>
CodePudding user response:
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;