Trying to get away from jQuery crutches and refactoring the bellow functions as plain JS.
//slide toggle navigation
$('#nav-toggle').click(function () {
$('.nav-list').slideToggle();
});
//toggle hamburger menu
$('#nav-toggle').click(function () {
this.classList.toggle('active');
});
I got the last one working as:
const toggle = document.getElementById('nav-toggle');
const navList = document.getElementsByClassName('nav-list');
toggle.addEventListener('click', function(e){
this.classList.toggle('active'); //toggle hamburger menu
e.preventDefault();
}, false);
I hit a blocker when I tried to pass both functionalities to the same click event:
//Add a click event listener
toggle.addEventListener('click', function(e){
//show hide div
if (navList.style.display == 'none') {
navList.style.display === 'block';
} else {
navList.style.display === 'none';
}
this.classList.toggle('active');
e.preventDefault();
}, false);
I have .nav-list as display none in my CSS.
Do I need separate event listeners for each event?
I tried that, but the error is still the same = TypeError: navList.style is undefined
Also, what would be the refactor for this nasty one bellow as plain JS?
$('nav ul li a:not(:only-child)').click(function (e) {
$(this).siblings('.nav-dropdown').toggle();
// Close one dropdown when selecting another
$('.nav-dropdown').not($(this).siblings()).hide();
e.stopPropagation();
});
You're out of jQuery, but you're still thinking in jQuery. navList is a NodeList object now, you need to iterate:
//Add a click event listener
toggle.addEventListener('click', function(e){
//show hide div
for( var i = 0; i < navList.length; ++i ){
if (navList[i].style.display == 'none') {
navList[i].style.display === 'block';
} else {
navList[i].style.display === 'none';
}
}
this.classList.toggle('active');
e.preventDefault();
}, false);
Edit:
This monstrosity should do the other fuction's job:
(function(){
var navDropdown = document.getElementsByClassName('nav-dropdown');
var nav = document.getElementsByTagName('nav');
for( var i = 0; i < nav.length; ++i ){
var ul = nav[i].getElementsByTagName('ul');
for( var j = 0; j < ul.length; ++j ){
var li = ul[j].getElementsByTagName('li');
for( var m = 0; m < li.length; ++m ){
var a = li[m].getElementsByTagName('a');
if( a.length > 0 ){
for( var k = 0; k < a.length; ++k ){
a[k].addEventListener('click', (function(a){
return function(e){
for( var n = 0; n < a.length; ++n ){
a[n].classList.toggle('nav-dropdown');
}
for( var o = 0; o < navDropdown.length; ++o ){
var found = false;
for( var n = 0; n < a.length; ++n ){
if( navDropdown[o] === a[n] ){
found = true;
break;
}
}
if( !found ){
navDropdown[o].classList.add('hide');
}
}
e.preventDefault();
};
})(a)
);
}
}
}
}
}
})();
It might very possibly be one of the worst things I've ever written, but it should work...
Obviously I can't check if it does without the actual page, but at least it runs.
you can iterate over a node list by using Array.from which will treat it as an array.
Array.from(navList).forEach(function(navItem){
navItem.style.display = navItem.style.display === 'none' ? 'block' : 'none';
})
You have the equal signs in your syntax crossed, should be:
if (navList.style.display === 'none') {
navList.style.display = 'block';
} else {
navList.style.display = 'none';
}
Quick cheat sheet:
= : assign
== : equals (also crosses javascript "type borders", i.e. 0 == "0" is true)
=== : strict equals (0 === "0" is false, 0 === 0 is true)
Related
I am trying to implement this code on my site:
Since it is a WordPress site made with page builder, I had to add all the anchor tags with jquery like this:
$('<a name="#A1"></a>').insertBefore('#header');
$('<a name="#A2">Tag #2.</a>').insertBefore('#services');
$('<a name="#A3">Tag #3.</a>').insertBefore('#portfolio');
$('<a name="#A4">Tag #4.</a>').insertBefore('#clients');
The code works, but when I try to scroll, nothing happens on the page.
I used this code that you can also see in my codepen
JS:
(function() {
var delay = false;
$(document).on('mousewheel DOMMouseScroll', function(event) {
event.preventDefault();
if(delay) return;
delay = true;
setTimeout(function(){delay = false},200)
var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;
var a= document.getElementsByTagName('a');
if(wd < 0) {
for(var i = 0 ; i < a.length ; i++) {
var t = a[i].getClientRects()[0].top;
if(t >= 40) break;
}
}
else {
for(var i = a.length-1 ; i >= 0 ; i--) {
var t = a[i].getClientRects()[0].top;
if(t < -20) break;
}
}
$('html,body').animate({
scrollTop: a[i].offsetTop
});
});
})();
How can I make the jquery Work?
I inspected the site and see this error duplicating everytime I try to scroll.
Here is the site am trying to test.
It is throwing error on this line of code -
var t = a[i].getClientRects()[0].top;
because a[i] for
<a href="#" class="zn-res-trigger zn-menuBurger zn-menuBurger--3--s zn-
menuBurger--anim1" id="zn-res-trigger">
<span></span>
<span></span>
<span></span>
</a>
don't have getClientRects() method.
So replace your code with
for(var i = 0 ; i < a.length ; i++) {
if(!a[i].className.includes('zn-res-trigger')) //add this check{
var t = a[i].getClientRects()[0].top;
...........
}
}
Also check with the help of debugger, may be there are other unused anchor tags, so you have to include check for them also
You have some a element that does not have top property which cause the undefined error.
try the bellow code in which I do check the a[i].getClientRects().length in order to get the top value :
(function() {
var delay = false;
$(document).on('mousewheel DOMMouseScroll', function(event) {
event.preventDefault();
if(delay) return;
delay = true;
setTimeout(function(){delay = false},200)
var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;
var a= document.getElementsByTagName('a');
var scroll = false;
if(wd < 0) {
for(var i = 0 ; i < a.length ; i++) {
if(a[i].getClientRects().length>0) {
scroll = true;
var t = a[i].getClientRects()[0].top;
if(t >= 40) break;
}
}
}
else {
for(var i = a.length-1 ; i >= 0 ; i--) {
if(a[i].getClientRects().length>0) {
scroll = true;
var t = a[i].getClientRects()[0].top;
if(t < -20) break;
}
}
}
if(scroll){
$('html,body').animate({
scrollTop: a[i].offsetTop
});
}
});
})();
I am trying to make a simple slide show to cycle through my images. The problem I'm having is when trying to select only the images in the "image_wrapper" div using document.getElementById("image_wrapper").getElementsByTagName("img")
is that it also selects the images from a sibling div. I only want to cycle through the images in the image_wrapper div.
The html onclick calls addOne() when the right arrow is clicked, and takeOne() when the left arrow is clicked
var x = 0;
var hideImage = document.getElementsByClassName("profile_image");
function displayOne() {
for(i = 0; i < hideImage.length; i++) {
if(i == 0) {
hideImage[0].style.display = "inline-block";
}
}
}
function addOne() {
var profileImg = document.getElementById("image_wrapper").getElementsByTagName("img");
if(x < profileImg.length ) {
x++;
} else {
x = 0;
}
for(i = 0; i < profileImg.length ; i++) {
if(x == profileImg.length) { x = 0;}
if(x == i) {
profileImg[i].style.display = "inline-block";
} else {
profileImg[i].style.display = "none";
}
}
}
function takeOne() {
var profileImg = document.getElementById("image_wrapper").getElementsByTagName("img");
if(x > 0 ) {
x--;
} else {
x += profileImg.length - 1 ;
}
for(i = 0; i < profileImg.length ; i++) {
if(x == -1) { x = profileImg.length; }
if(x == i) {
profileImg[i].style.display = "inline-block";
} else {
profileImg[i].style.display = "none";
}
}
}
Have you tried;
document.querySelectorAll('#image_wrapper img');
document.querySelectorAll() and document.querySelector() can take css selectors.
So I have a simple layout of,
<a name="#A1"></a>
<div></div>
<a name="#A2"></a>
<div></div>
<a name="#A3"></a>
<div></div>
And Im using the script below to jump to the next anchor point on mouse scroll event. I have tested it and it works on Firefox and IE but on Chrome only scrolling down works, when you scroll up nothing happens.
(function() {
var delay = false;
$(document).on('mousewheel DOMMouseScroll', function(event) {
event.preventDefault();
if(delay) return;
delay = true;
setTimeout(function(){delay = false},200)
var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;
var a= document.getElementsByTagName('a');
if(wd < 0) {
for(var i = 0 ; i < a.length ; i++) {
var t = a[i].getClientRects()[0].top;
if(t >= 40) break;
}
}
else {
for(var i = a.length-1 ; i >= 0 ; i--) {
var t = a[i].getClientRects()[0].top;
if(t < -20) break;
}
}
$('html,body').animate({
scrollTop: a[i].offsetTop
});
});
})();
The error that im getting is Uncaught TypeError: Cannot read property 'top' of undefined
From the specification
If the element on which it was invoked does not have an associated
layout box return an empty sequence and stop this algorithm.
getClientRects() function may return empty list. So element at [0] index may not exist (undefined). Thus you should check length of the list before accessing element in it.
Changed "getElementsByTagName" to "getElementsByClassName"
(function() {
var delay = false;
$(document).on('mousewheel DOMMouseScroll', function(event) {
event.preventDefault();
if(delay) return;
delay = true;
setTimeout(function(){delay = false},200)
var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;
var a = document.getElementsByClassName("full-height");
if(wd < 0) {
for(var i = 0 ; i < a.length ; i++) {
var t = a[i].getClientRects()[0].top;
if(t >= 40) break;
}
}
else {
for(var i = a.length-1 ; i >= 0 ; i--) {
var t = a[i].getClientRects()[0].top;
if(t < -20) break;
}
}
$('html,body').animate({
scrollTop: a[i].offsetTop
});
});
})();
This doesn't look right if you're trying to get the computed top of an element.
var t = a[i].getClientRects()[0].top;
This should use offsetTop.
var t = a[i].getClientRects()[0].offsetTop;
So Basicly if i click the burtton, it should change the variables to 1.
However, it dosen't print out "It's happening now" as it should.
Could someone please explain what's wrong with this??
Best regards daniel.
var reg_uname_done = 0;
var reg_pword1_done = 0;
var reg_pword2_done = 0;
var reg_email_done = 0;
$("#first_nav_bar li:first").click(function(event) {
reg_uname_done = 1;
reg_pword1_done = 1;
reg_pword2_done = 1;
reg_email_done = 1;
});
if(reg_pword1_done === 1 && reg_pword2_done === 1 && reg_email_done === 1 && reg_uname_done === 1) {
console.log('its happening now');
}
The reason why this is not happening is b/c the js file is going down, and you haven't "clicked" the <li> element yet, therefore your variables are still equal to 0. You have to set a function inside of that event.
See fiddle
var reg_uname_done = 0;
var reg_pword1_done = 0;
var reg_pword2_done = 0;
var reg_email_done = 0;
$("#first_nav_bar li:first").click(function (event) {
reg_uname_done = 1;
reg_pword1_done = 1;
reg_pword2_done = 1;
reg_email_done = 1;
check();
})
function check() {
if (reg_pword1_done === 1 && reg_pword2_done === 1 && reg_email_done && reg_uname_done) {
console.log('its happening now');
}
}
I am having trouble setting the parameter which JS will get the ID/Name of the element when the event occurs.
(function GostoListen() {
var inputs = document.getElementsByTagName("a");
for (x = 0 ; x < inputs.length ; x++) {
myname = inputs[x].getAttribute("ID") != null ? inputs[x].getAttribute("ID") : "next" ;
if (myname.indexOf("My_lnk") == 0) {
document.getElementById(myname).addEventListener("click", function () {
getElementById(??????????????).value = "CLICKED";
}, false);
}
}
}());
You should be able to access the element by using this. Within the context of the function you're creating this references the clicked element.
See this edited version:
(function GostoListen() {
var inputs = document.getElementsByTagName("a");
for (x = 0 ; x < inputs.length ; x++) {
myname = inputs[x].getAttribute("ID") != null ? inputs[x].getAttribute("ID") : "next" ;
if (myname.indexOf("My_lnk") == 0) {
document.getElementById(myname).addEventListener("click", function () {
this.value = "CLICKED";
}, false);
}
}
}());