Jump to content

making a menu controlled by arrow keys with marker


mathmagic

Recommended Posts

Hey everyone,I'm new here, and also quite new to coding. I finished javascript, jquery & html + css courses at codecademy (great website for beginners) and I'm currently making a mock-up website, just for experimentation.

 

I'm trying to make a menu that can be controlled by the arrow keys but I can't seem to get it right. I want a marker in front of the selected item to move up & down. My menu consists of a few list elements of which I turned off the markers. At the moment the section of my code looks like this:

 

The HTML:

<div class="menu">	<ul>    	<li class="selected">Home</li>        <li>Work</li>        <li>About</li>        <li>Contact</li>    </ul></div>

The CSS (the display: none is because I let it fade in in jquery, but this isn't relevant for my question):

.menu ul {	 font-family: Julius Sans One;	 font-weight:bold;	 display: none;	 margin-top:35px;	 margin-left: 0px;	 position: relative;	 list-style-type: none;	}li {	margin-top:20px;	}	.selected {	list-style-type: square;}

The jQuery:

var main = function(){		$(document).keydown(function(event) {        if (event.keyCode === 40){			$('.selected').removeClass('selected');			$('.selected').next().addClass('selected');			}		else if (event.keyCode === 38){			$('.selected').removeClass('selected');			$('.selected').prev().addClass('selected');		}    });		};$(document).ready(main);

So basically, I want to add the class 'selected' to the selected element and remove it from the previous. Like this, my marker just disappears when I press my arrow down or arrow up key. If I remove the first line in the if and else if statement, it adds the markers but doesn't remove the ones on the previous line, so if i pres all the way down to the end of the menu, there are markers in front of all the menu items.

 

I tried to google it, but my coding brain isn't trained that well yet and I couldn't really find cases that were similar enough to apply the methods to my code. If someone more experienced could help me out with this one, that would be great.

Edited by mathmagic
Link to comment
Share on other sites

In your code, removing the "selected" class from the element will mean that you can't use ".selected" to target the element in the next line.

 

What I would do is to have a list of all the elements and a pointer to the current one. Change the pointer each time a key is pressed, then remove the class from any element in the list before adding it to the current one.

/* These are global */var currentItem = 0;var items = $(".menu li");/* Inside the event handler */$(document).keydown(function(event) {    if (event.keyCode === 40) {        // Move to the next element        currentItem++;        // Use only one of these            // Either stop at last item            if(currentItem >= items.length) currentItem = items.length - 1;            // Or return to first item            if(currentItem >= items.length) currentItem = 0;        ////////    } else if (event.keyCode === 38){        // Move to the previouselement        currentItem++;        // Use only one of these            // Either stop at first item            if(currentItem < 0) currentItem = 0;            // Or move to last item            if(currentItem < 0) currentItem = items.length - 1;        ////////    }    // Remove selected class from all elements    items.removeClass("selected");    // Add selected class to current item    items.eq(currentItem).addClass("selected");}
Link to comment
Share on other sites

Okay so I tried to grasp this, still having troubles.

 

I used your code and made a separate case for every selected item and gave every list item a separate ID. Now it does another weird thing. At first the first item doesn't seem selected, when I push down, a marker appears in front of the second element. When I push down again, the marker stays on the second line.

 

Here's the code:

 

html:

<div class="menu">	<ul>    	<li ID="li1">Home</li>        <li ID="li2">Work</li>        <li ID="li3">About</li>        <li ID="li4">Contact</li>    </ul></div>

javascript:

var main = function(){	$(document).keydown(function(event) {        var currentItem = 0;		if (event.keyCode === 40){			currentItem++;			if (currentItem >= $('.menu li').length){				currentItem = 0;				}			}		else if (event.keyCode === 38){			currentItem--;			if (currentItem < 0) {				currentItem = $('.menu li').length;				}			}		switch(currentItem){						case 0:				$('#li4').removeClass('selected');				$('#li1').addClass('selected');				break;						case 1:				$('#li1').removeClass('selected');				$('#li2').addClass('selected');				break;							case 2:				$('#li2').removeClass('selected');				$('#li3').addClass('selected');				break;							case 3:				$('#li3').removeClass('selected');				$('#li4').addClass('selected');				break;						}        });	};$(document).ready(main);

What did I do wrong?

Link to comment
Share on other sites

Wow took me a while to figure it out, but finally got it, I had to look up the .eq command because I didn't know about it yet.

 

IT FINALLY WORKS, thank you!

 

I still have another question, in the code I made I also have another function, so I thought that I had to define the variable 'currentItem' in between the brackets of my new function. If I did it like this, my marker only hopped between the second and last list item. do you have an explanation for this? If I place it all the way at the start of the code it works fine

 

(I mean like this):

var main = function(){		$(document).keydown(function(event) {        var currentItem = 0;		//blablabla    });		};$(document).ready(main);

versus:

var currentItem = 0;var main = function(){		$(document).keydown(function(event) {		//blablabla    });		};$(document).ready(main);
Edited by mathmagic
Link to comment
Share on other sites

If currentItem is in the event handler it gets set to zero every time you press a key. Its value need to be remembered, so it must remain in the global scope.

$(document).keydown(function(event) {    var currentItem = 0;    // Current item is always zero at this point because you just set it in the previous line    currentItem++; // Current item is 0 + 1 which is 1.    //    // . . .}
Link to comment
Share on other sites

  • 1 year later...

Sorry to necro, but...

 

In your code, removing the "selected" class from the element will mean that you can't use ".selected" to target the element in the next line.

 

What I would do is to have a list of all the elements and a pointer to the current one. Change the pointer each time a key is pressed, then remove the class from any element in the list before adding it to the current one.

/* These are global */var currentItem = 0;var items = $(".menu li");/* Inside the event handler */$(document).keydown(function(event) {    if (event.keyCode === 40) {        // Move to the next element        currentItem++;        // Use only one of these            // Either stop at last item            if(currentItem >= items.length) currentItem = items.length - 1;            // Or return to first item            if(currentItem >= items.length) currentItem = 0;        ////////    } else if (event.keyCode === 38){        // Move to the previouselement        currentItem++;        // Use only one of these            // Either stop at first item            if(currentItem < 0) currentItem = 0;            // Or move to last item            if(currentItem < 0) currentItem = items.length - 1;        ////////    }    // Remove selected class from all elements    items.removeClass("selected");    // Add selected class to current item    items.eq(currentItem).addClass("selected");}

It's hard to copy this code because it's all been placed on one line. I wonder, do you still have a copy of the correctly formatted code?

 

Thanks.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...