Reputation: 149
I'm making a dropdown responsively. I made two dropdown-divs for both desktop version and mobile version. The problem is, as I initialize the mobile-version dropdown with a property 'display:none;', the addEventListener bound to it throws an error.
userinfoBtnMobile.addEventListener('click',function() {
const userinfoDropdownStyle = window.getComputedStyle(userinfoDropdownMobile);
const userinfoDropdownDisplayValue = userinfoDropdownStyle.getPropertyValue('display');
if(userinfoDropdownDisplayValue === 'none') {
userinfoDropdownMobile.style.display = 'block';
} else {
userinfoDropdownMobile.style.display = 'none';
}
});
Below is an error shown in console of the browser.
Uncaught TypeError: Cannot read property 'addEventListener' of null
However, as I changed it to the one using jQuery, this error disappears. (Please ignore internal logic. It logically do a same function.)
userinfoBtnMobile.click(function() {
if(userinfoDropdownMobile.is(':visible')) {
userinfoDropdownMobile.slideUp();
} else {
userinfoDropdownMobile.slideDown();
}
})
So, I assume that it seems like, as 'addEventListener' is triggered before the div's value of display property turned into 'block', it finds 'null' when targeting while jQuery's .click() is triggered when the specific 'click' event trigger so that it does not throw any error. Is that right?
What's difference between two ways?
Upvotes: 0
Views: 37
Reputation: 371168
jQuery's .click
returns a jQuery collection.
.click
can be called on a jQuery collection to add an event listener to all matched elements. If no elements happen to be matched, no error is thrown; there just aren't any elements that happen to be iterated over.
But querySelector
doesn't return a collection, but a single element, the first one found that matches the selector. If no elements are found, it'll return null
.
In this case, it sounds like no elements matching the selector are found in the DOM when addEventListener
is called.
To more fully replicate jQuery's logic, use querySelectorAll
:
for (const element of document.querySelectorAll('some-selector')) {
element.addEventListener('click', function() {
});
}
If you replace your original code with this, no errors will be thrown (but, just like in all the versions, no elements will be selected, so no click listeners will be attached).
That's why the addEventListener
throws but jQuery's .click
doesn't - but the script still isn't functional, since the elements you want don't exist in the DOM when the script runs. To fix that, run the script only after the DOM is populated: put the script in an external file and give it the defer
attribute.
<script src="path-to-script" defer></script>
(see this question)
Upvotes: 1