loop through nav menu when li menu's hovered - javascript

I am not familar with JavaScript DOM , mostly i use jQuery for script.. I am trying on JavaScript and in trouble with the below code.
Does anyone know what could be the problem?
What i would like to do is when LI is hovered, the nested OL is displayed..somehow, the below code doesn't work, even it doesn't show any error in console.
Please help me...
var ul = document.querySelector('.gnb');
var li = ul.children;
var ol = document.getElementsByTagName('ol');
var i;
for (i = 0; i < li.length; i++) {
li[i].addEventListener('mouseenter', myFunction(myshow));
li[i].addEventListener('mouseleave', myFunction(myhide));
}
function myshow() {
ol.style.display = 'block'
}
function myhide() {
ol.style.display = 'none'
}
function myFunction(fn) {
return function(e) {
if (e.target.type !== "mouseenter") return;
fn.call(e.target)
};
}
.gnb {
float: left;
margin-left: 30px;
width: auto;
height: 100%;
}
.gnb>li {
float: left;
width: 150px;
height: 100%;
list-style: none;
}
.sub {
display: none;
}
.sub.show {
display: block;
}
<ul class="gnb">
<li class="gnbLi">
Why Mailchimp?
</li>
<li class="gnbLi" onmouseenter="myFunction()">
What You Can Do
<ol class="sub">
<li>Overview</li>
<li>Create</li>
</ol>
</li>
</ul>

Problem:
Basically what you have done is dealing with an array as a single element because of getElementsByTagName returns an array of ol in the whole page.
Solve:
1. you need to get the nested ol inside the li that's being hovered using
-event.target to get the clicked li.
- querySelector to get the ol under that li.
2. you need the ol to be displayed/removed depending on the event.
so only change the Javascript to be as the following and it will work
var ul = document.querySelector('.gnb');
var li = ul.children;
for (i = 0; i < li.length; i++) {
li[i].addEventListener('mouseenter', mouseenter);
li[i].addEventListener('mouseleave',mouseleave );
}
function mouseenter(event) {
var ol = event.target.querySelector('ol');
if(ol){
ol.style.display = 'block';
}
}
function mouseleave(event) {
var ol = event.target.querySelector('ol');
if(ol){
ol.style.display = 'none';
}
}

Your code is not correct and clean, I changed a little bit of your code:
(function () {
var ul = document.querySelector('.gnb');
var li = ul.children
var ol = document.getElementsByTagName('ol')[0];
var i;
for (i = 0; i < li.length; i++) {
li[i].addEventListener('mouseenter', myFunction(myshow));
li[i].addEventListener('mouseleave', myFunction(myhide));
}
function myshow() {
ol.style.display = 'block'
}
function myhide() {
ol.style.display = 'none'
}
function myFunction(fn) {
return fn;
}
})();
.gnb {
float: left;
margin-left: 30px;
width: auto;
height: 100%;
}
.gnb > li {
float: left;
width: 150px;
height: 100%;
list-style: none;
}
.sub {
display: none;
}
.sub.show {
display: block;
}
<ul class="gnb">
<li class="gnbLi">
Why Mailchimp?
</li>
<li class="gnbLi">
What You Can Do
<ol class="sub">
<li>Overview</li>
<li>Create</li>
</ol>
</li>
</ul>

Related

Image slider: back an image

So I followed a tutorial on how to create image slider with jquery but he didn't show how to add next image and previous image, so I'm trying to do that my self. The next image part is working but I can't get previous image to work. https://jsfiddle.net/vmab7xk6/10/
//slider
var sliderWidth = 960;
var sliderSpeed = 1000;
var sliderPause = 5000;
var sliderCurrent = 1;
var sliderInterval;
var $sliderLocation = $(".slider");
var $sliderContainer = $sliderLocation.find(".slides");
var $sliderSlides = $sliderContainer.find(".slide");
// img slider
function startSlider() {
sliderInterval = setInterval(function() {
$sliderContainer.animate({'margin-left': '-='+sliderWidth}, sliderSpeed, function() {
sliderCurrent++;
if(sliderCurrent === $sliderSlides.length) {
sliderCurrent = 1;
$sliderContainer.css("margin-left", 0);
}
});
}, sliderPause);
}
function pauseSlider() {
clearInterval(sliderInterval);
}
function backSlider() {
$sliderContainer.animate({"margin-left": "+="+sliderWidth}, sliderSpeed, function() {
sliderCurrent--;
if(sliderCurrent === $sliderSlides.length) {
sliderCurrent = $sliderSlides.length - 1;
$sliderContainer.css("margin-left", "-1920");
}
});
}
function nextSlider() {
$sliderContainer.animate({"margin-left": "-="+sliderWidth}, sliderSpeed, function() {
sliderCurrent++;
if(sliderCurrent === $sliderSlides.length) {
sliderCurrent = 1;
$sliderContainer.css("margin-left", 0);
}
});
}
$("#sliderControllsLeft").on("click", function() {
backSlider();
console.log("left");
});
$("#sliderControllsPause").on("click", function() {
pauseSlider();
console.log("pause");
});
$("#sliderControllsStart").on("click", function() {
startSlider();
console.log("start");
});
$("#sliderControllsRight").on("click", function() {
nextSlider();
console.log("right");
});
startSlider();
<section class="slider">
<ul class="slides">
<li class="slide"><img src="img/slider_01.jpg"></li>
<li class="slide"><img src="img/slider_02.jpg"></li>
<li class="slide"><img src="img/slider_03.jpg"></li>
<li class="slide"><img src="img/slider_01.jpg"></li>
</ul>
<ul class="sliderControlls">
<li id="sliderControllsLeft"><</li>
<li id="sliderControllsPause">=</li>
<li id="sliderControllsStart">+</li>
<li id="sliderControllsRight">></li>
</ul>
</section>
section.slider {
width: 100%;
height: 500px;
overflow: hidden;
margin: 100px 0;
}
section.slider .slides {
display: block;
width: 6000px;
height: 400px;
margin: 0;
padding: 0;
}
section.slider .slide {
width: 960px;
height: 400px;
float: left;
list-style-type: none;
}
ul.sliderControlls {
list-style-type: none;
}
ul.sliderControlls li {
display: inline-block;
font-size: 60px;
color: #000;
text-decoration: none;
padding: 0 10px 0 10px;
}
You have a few syntax errors. See updated fiddle: jsfiddle
You needed to declare the jQuery shorthand $ before using it. I added a wrapper function that does that. On your JS, (at least on the fiddle), you did not include your slider variables - I added those.

How to change class and text of one tag by clicking on another tag?

I don't know how to describe this without making it more complicated.
So look at the result of the code and click on the first link with "Show", then the second one and third one.
When the second link is clicked, first one closes but text remains "Hide" and i want it to change to "Show".
So, when clicking a link, detect if any other link has text "Hide" and change it to "Show".
And please no jQuery...
document.getElementsByClassName("show")[0].onclick = function() {
var x = document.getElementsByClassName("hide")[0];
var y = document.getElementsByClassName("show")[0];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
document.getElementsByClassName("show")[1].onclick = function() {
var x = document.getElementsByClassName("hide")[1];
var y = document.getElementsByClassName("show")[1];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
document.getElementsByClassName("show")[2].onclick = function() {
var x = document.getElementsByClassName("hide")[2];
var y = document.getElementsByClassName("show")[2];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
function closeOther() {
var visible = document.querySelectorAll(".visible"),
i, l = visible.length;
for (i = 0; i < l; ++i) {
visible[i].classList.remove("visible");
}
}
.style {
background-color: yellow;
width: 200px;
height: 200px;
display: inline-block;
}
.hide {
background-color: red;
width: 50px;
height: 50px;
display: none;
position: relative;
top: 50px;
left: 50px;
}
.hide.visible {
display: block;
}
<div class="style">
Show
<div class="hide">
</div>
</div>
<div class="style">
Show
<div class="hide">
</div>
</div>
<div class="style">
Show
<div class="hide">
</div>
</div>
I tried to write a solution which didn't use any javascript at all and worked using CSS alone. I couldn't get it to work though - CSS can identify focus but it can't identify blur (ie. when focus has just been removed).
So here is a solution which uses javascript and the classList API, instead:
var divs = document.getElementsByTagName('div');
function toggleFocus() {
for (var i = 0; i < divs.length; i++) {
if (divs[i] === this) continue;
divs[i].classList.add('show');
divs[i].classList.remove('hide');
}
this.classList.toggle('show');
this.classList.toggle('hide');
}
for (let i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', toggleFocus, false);
}
div {
display: inline-block;
position: relative;
width: 140px;
height: 140px;
background-color: rgb(255,255,0);
}
.show::before {
content: 'show';
}
.hide::before {
content: 'hide';
}
div::before {
color: rgb(0,0,255);
text-decoration: underline;
cursor: pointer;
}
.hide::after {
content: '';
position: absolute;
top: 40px;
left: 40px;
width: 50px;
height: 50px;
background-color: rgb(255,0,0);
}
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
Like this?
Just added following to closeOther():
visible = document.querySelectorAll(".show"),
i, l = visible.length;
for (i = 0; i < l; ++i) {
visible[i].textContent="Show";
}

How to have two different bgcolor changing events

I'm trying to have a bgcolor change for an element on mouseover, mouseout, and onclick. The problem is Javascript overwrites my onclick with mouseout, so I can't have both. So is there any way to have mouseover reset after mouseout?
function init() {
document.getElementById('default').onmouseover = function() {
tabHoverOn('default', 'grey')
};
document.getElementById('default').onmouseout = function() {
tabHoverOff('default', 'yellow')
};
document.getElementById('section2').onmouseover = function() {
tabHoverOn('section2', 'grey')
};
document.getElementById('section2').onmouseout = function() {
tabHoverOff('section2', 'yellow')
};
document.getElementById('section3').onmouseover = function() {
tabHoverOn('section3', 'grey')
};
document.getElementById('section3').onmouseout = function() {
tabHoverOff('section3', 'yellow')
};
}
function tabHoverOn(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
function tabHoverOff(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
var current = document.getElementById('default');
function tab1Highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab1highlight";
current = id;
}
function tab2highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab2highlight";
current = id;
}
function tab3highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab3highlight";
current = id;
}
window.onload = init();
body {
width: 900px;
margin: 10px auto;
}
nav {
display: block;
width: 80%;
margin: 0 auto;
}
nav > ul {
list-style: none;
}
nav > ul > li {
display: inline-block;
margin: 0 3px;
width: 150px;
}
nav > ul > li > a {
width: 100%;
background-color: #ffff66;
border: 1px solid #9b9b9b;
border-radius: 12px 8px 0 0;
padding: 8px 15px;
text-decoration: none;
font-weight: bold;
font-family: arial, sans-serif;
}
main {
display: block;
width: 80%;
margin: 0 auto;
border: 1px solid #9b9b9b;
padding: 10px;
}
main > h1 {
font-size: 1.5em;
}
.tab1highlight {
background-color: #339966;
color: white;
}
.tab2highlight {
background-color: #ff6666;
color: white;
}
.tab3highlight {
background-color: #6600ff;
color: white;
}
main img {
border: 5px solid #eeefff;
width: 80%;
margin-top: 20px;
}
<body>
<nav>
<ul>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>
</nav>
<main>
<h1>Exercise: Navigation Tab #5</h1>
<ul>
<li>
Combine the navigation tab exercises #1, #3, and #4 in one file, including <br>
<ul>
<li>temporarily change the background color of a tab when the cursor is hovering on it.</li>
<li>set the foreground and background color of the tab being clicked.</li>
<li>change the background color of the main element based on the selected tab.</li>
</ul>
<p>
To test, click on a tab and then move your mouse around. For example, the third tab is clicked, the tab background color is switched to blue. Then hover the mouse over the third tab, the background color of the tab should be switch to light green and then back to blue after the mouse moves out.
</p>
<img src="menu_tab5.jpg">
</li>
</ul>
</main>
It's generally a good idea to keep CSS out of JavaScript completely if you can help it. A better strategy for solving the hover problem is to use the CSS pseudo selector :hover rather than coding the color changes in JavaScript. If you give all your tabs the same class, you only have to write the CSS once:
.tab {
background-color: yellow;
}
.tab:hover {
background-color: grey;
}
Once you've done that, you can also relegate the click styling to CSS by creating an event handler that adds and removes a special class each time a tab is clicked.
In the CSS file:
.tab.clicked {
background-color: blue;
}
And then in JavaScript, something like:
var tabs = document.getElementsByClassName('tab');
for (i = 0; i < tabs.length; i ++) {
tabs[i].onclick = function (ev) {
for (i = 0; i < tabs.length; i ++) {
tabs[i].classList.remove('clicked');
}
ev.currentTarget.classList.add('clicked');
};
}
I've created a JSFiddle to illustrate.
Try updating a Boolean variable.
var Ele = document.getElementById('default');
var clicked = false;
Ele.onclick = function(){
clicked = true;
// add additional functionality here
}
Ele.onmouseover = function(){
clicked = false;
// add additional functionality here
}
Ele.onmouseout = function(){
if(!clicked){
// add additional functionality here
}
}

How to animate the list?

This is my JSFiddle
As you can see from the fiddle that there is a list that is being scrolled with the help of arrows.. So what I want is to animate that transition when the list visible and hidden.
I don't know about the animation. I have seen many examples and tried to adjust them with my example but it's not working... How do I get the list to animate?
$(document).ready(function(){
var code='';
for(var i=1;i<=20;i++)
{
code+="<li>list Item "+i+"</li>";
}
$('#list-items').html(code);
});
var list_items = [];
var index = 0;
var list_length = 0;
function getAllListItems() {
var temp = document.getElementsByTagName('li');
for (i = 0; i < temp.length; i++) {
list_items.push(temp[i]);
}
list_length = temp.length;
}
getAllListItems();
function move(dir) {
if (dir == left) {
list_items[index].style.display = 'block';
index--;
if (index < 0) {
index = 0;
}
} else if (dir == right) {
list_items[index].style.display = 'none';
if (index >= ((list_length) - 1)) {
index = (list_length) - 1;
} else {
index++;
}
} else {}
}
* {
box-sizing: border-box;
}
ul {
float:left;
height:50px;
width: 600px;
overflow: hidden;
}
ul li {
text-align: center;
border: 2px solid black;
width: 100px;
height: 50px;
float: left;
list-style-type: none;
background-color: aquamarine;
}
ul li:first-child {
display: block;
}
#left, #right {
float:left;
height:50px;
background-color:aqua;
font-size:2em;
padding-left: 20px;
padding-right:20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body onload='getAllListItems()'>
<div id='t'></div>
<button id='left' onClick="move(left)">
<</button>
<ul id='list-items'>
</ul>
<button id='right' onClick='move(right)'>></button>
</body>
You can easily just replace your lines:
list_items[index].style.display = 'block';
list_items[index].style.display = 'none';
with the jQuery show() and hide() functions:
$(list_items[index]).show("slow");
$(list_items[index]).hide("slow");
As demonstrated in my updated version of your Fiddle
For different transitions, you can use the animate() function, which lets you tell it what css properties to affect. In addition to numeric values, jQuery also supports the special values 'show', 'hide', and 'toggle' (which, incidentally, will show, hide, or toggle the show/hide status of an element using that property). So for instance, if you wanted to shrink them only horizontally and leave the vertical alone, you could change the .show() and .hide() calls to:
$(list_items[index]).animate({width:'show'}, 600);
$(list_items[index]).animate({width:'hide'}, 600);
I've demonstrated this in another updated Fiddle

How do I expand this CSS list?

I've gotten my menu to expand by one level, but cannot figure out how to get it to expand a second time. What am I doing wrong?
HTML:
<ul id="nav">
<li>Root
<ul>
<li>Option 1
<ul>
<li>Link3</li>
<li>Lin4</li>
<li>Link5</li>
<li>Link6</li>
</ul>
</li>
<li>Option2
<ul>
<li>Link3</li>
</ul>
</li>
</ul>
</li>
</ul>
CSS:
ul {
padding: 0px;
margin: 0px;
list-style: none;
background-color: #53BF58;
width: 10em;
}
li ul {
display: none;
background-color: #86EF8A;
}
li.active ul {
display: block;
}
li ul li ul {
display: none;
background-color: #86EF8A;
}
li ul li.active ul {
display:block;
}
Javascript:
function hideAll() {
var navList = document.getElementById("nav");
for (var i=0; i<navList.childNodes.length; i++) {
var node = navList.childNodes[i];
if (node.tagName == "LI") {
node.className = node.className.replace(new RegExp("\s?active", "i"), "");
}
}
}
window.onload = function () {
var navList = document.getElementById("nav");
for (var i=0; i<navList.childNodes.length; i++) {
var node = navList.childNodes[i];
if (node.tagName == "LI") {
node.onclick = function() {
hideAll();
this.className += " active";
}
}
}
}
childNodes only contains the direct children of the element--you need to recurse the childNodes of each node as well.
I highly recommend that you use a framework like jQuery (http://jquery.com) to make the code simpler:
http://jsfiddle.net/jDEhU/5/
$('#nav').delegate('li', 'click', function() {
var self = $(e.target), //get a reference to the clicked element
active = self.parents().andSelf() //select all li's that should be active
.addClass('active'); //and activate them
$('#nav .active').not(active).removeClass('active'); //deactivate others
});
I think the problem is that you're only looping through the first level of nodes in your list. You need to go through the child elements of each subsequent list and add an onClick function to keep it expanding.

Categories

Resources