Positioning nested element in response to arrow key - Javascript/jQuery/CSS

I’m relatively inexperienced with JavaScript and jQuery, but I’ve figured out how to cause a response to an arrow button press. However, I would like a nested element to change its position in response to the arrow button press. I’ve tried using

document.getElementById("item").style.left = 10px;
  • That causes the parent element to change its position to 10px left of the window. I’m using IE as the test browser.

Eventually, the item will only go to the width of the parent tag. I know how to calculate that, but I first need to get the nested element to move, say 10px to the right whenever the right arrow key is pressed. Any help would be greatly appreciated.

Here is my complete code:



<!DOCTYPE HTML>
<html>
	<head>
		<title>Practice</title>
		<style type="text/css">
		.holder
		{
		  position: relative;
		  top:100px;
		  left:100px;
		  border:2px solid;
		  border-color:blue;
		  width:200px;
		  height:200px;
		  z-index:1;
		}

		.base
		{
		  position: relative;
		  top:190px;
		  left:0px;
		  background-color: black;
		  width:50px;
		  height:10px;
		  z-index:2;
		}
 		</style>
 		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
 		<script type="text/javascript">
 			function goRight() {
 				var lzrItem = document.getElementById("base");
 				lzrItem.style.left = "10px";
 			}
 		</script>
 		<script>
		    $(document).keydown(function(event) {
		      switch (event.keyCode) {
	            case 37:
	            	alert('left');
	            	break;
		        case 38:
		        	alert('up');
		        	break;
		        case 39:
		        	x = $(".base").position();
		        	alert(x.top);
		        	alert(x.left);
		        	alert('You pressed the right arrow');
		        	goRight();
		        	break;
		        case 40:
		        	alert('down');
		        	break;
		      }
		    });
        </script>
	</head>
	<body>
		<div class="holder" id="holder" >
			<div class="base" id="base">
			</div>
		</div>
	</body>
</html>


Thanks,
Mike

Hi Mike,

Thanks for a well asked question :slight_smile:

It’s always nice to get a good bit of source code posted to work with :slight_smile:

Since you’re already using jQuery, let’s continue with that approach.

If you want to move an element, you can set it’s CSS position using the jQuery .css() method. In this case, the “goRight()” function will be called everytime the keydown event ticks over.

To move the element, we simply need to get its current left position and add 10 to it.


function goRight() {
    $b = $("#base");
    $b.css("left", $b.position().left + 10);
}

You can write similar functions for the up, down and left directions (tip: when moving left, don’t set the “right” css value, but decrease the left value by the desired amount)

Now, as for the “bounding”, keeping the “base” inside of the “holder”:

For the right bound you’ll want to limit the maximum left value to the width of the box minus the width of the element that’s moving.

For the bottom bound you’ll want to limit the maximum top value to the height of the box minus the height of the element that’s moving.

For the left and top bounds, it the maximum value would be set to zero if they become negative.

I modified your code and have a local working example of how the bounding could work, so if you get really stuck with it, let me know and I’ll send you a jsFiddle :slight_smile:

To be able easily to read CSS properties of an element, they need to be applied inline.

Here’s a working example without jQuery.

To simplify calculations, border width isn’t considered.

A function table is usually prefereable to switch-case.

<!DOCTYPE HTML>
<html>
    <head>
        <title>Practice</title>
        <style type="text/css">
        .holder
        {
          position: relative;
          top:100px;
          left:100px;
          border:2px solid;
          border-color:blue;
          width:200px;
          height:200px;
          z-index:1;
        }

        .base
        {
          position: relative;
          top:190px;
          left:0px;
          background-color: black;
          width:50px;
          height:10px;
          z-index:2;
        }
        </style>
    </head>
    <body>
        <div class="holder" id="holder" >
            <div class="base" id="base" style='top:190px;left:0px'>
            </div>
        </div>
        <script type='text/javascript'>

            function moveDiv( elem, step )
            {
              var funcs = [],
                  st = elem.style,
                  op = elem.parentNode,
                  hTravel = op.offsetWidth - elem.offsetWidth,
                  vTravel = op.offsetHeight - elem.offsetHeight;

              funcs[ 'f37' ] = function(){ st.left = ( d = parseInt( st.left ) ) - Math.min( step, d ) + 'px'; }
              funcs[ 'f39' ] = function(){ st.left = ( d = parseInt( st.left ) ) + Math.min( step, hTravel - d ) + 'px'; }
              funcs[ 'f38' ] = function(){ st.top = ( d = parseInt( st.top ) ) - Math.min( step, d ) + 'px'; }
              funcs[ 'f40' ] = function(){ st.top = ( d = parseInt( st.top ) ) + Math.min( step, vTravel - d ) + 'px'; }

              return function( evt )
              {
                var e = evt || window.event,
                    key = e.keyCode || e.which,
                    fName = 'f' + key;

                funcs[ fName ] ? funcs[ fName ]() : 0;
              }
            }

            document.onkeydown = moveDiv( document.getElementById( 'base' ), 5 );
        </script>
    </body>
</html>

Sad but true, which is why libraries are handy, they abstract this “inconvenience” away :slight_smile:

It’s not too hard to implement something like this though. If you wanted to take a non-jquery approach you could roll-your-own “getStyle” method:


var theElement = document.getElementById("base");

function getStyle(el, prop){
    if (el.currentStyle) {
        return el.currentStyle[prop]
    }
    else if (window.getComputedStyle) {
        return window.getComputedStyle(el,null).getPropertyValue(prop);  
    }
    return false;
}

 getTheStyle(theElement,"top");

Hi AussieJohn

That worked thank you. I had finally figured out how to do make it work using basic JavaScript (primarily because I couldn’t figure it out with jQuery). Your jQuery recommendation works well and is easier to read, so I’m using jQuery. I had tried to use jQuery initially, but I think I was mixing it with JavaScript. for example, I was trying to declare a basic JavaScript variable and then apply jQuery methods to it.

Anyway, thanks again. You recommendation solved my problem.