0

Please excuse my ignorance, I only started writing javascript recently. I am not looking for an out-of-the-box solution, but more some insight that will help me to write the code myself.

I am working on a full-screen, sliding-panel type website, with the option to navigate using either arrow keys or clickable links.

I've got it all functioning nicely when navigating with the arrow keys, and what I want to do is to call the same functions when using the on-screen navigation links. I am not sure how to do this, as the functions and variables are declared inside the key binding function.

My second problem is that I need a way to prevent the slide functions from being called more than once while the function is still animating. I have tried various setTimeout implementations, and also Ben Alman's doTimeout and debounce, but can't seem to get it working properly.

Any help would be greatly appreciated!

Here is a jsFiddle with a simplex version of what I have built : http://jsfiddle.net/BKpAK/3/

And here is just the JS if you don't want to fiddle:

$(document).ready(function () {         

var currentSlide = 1;

$(document).keydown(function(e){

    nextSlide = currentSlide + 1;
    prevSlide = currentSlide - 1;

    lastSlide = $(".slide").length

    cur1 = document.getElementById("slide" + currentSlide);
    prev1 = document.getElementById("slide" + prevSlide);
    next1 = document.getElementById("slide" + nextSlide);

    function moveRight(){
      if(currentSlide < lastSlide){
        $(next1).addClass('frontAndCenter').stop().animate({
          left: "0",
        }, 500, function() {
          $(this).removeClass("frontAndCenter");
          $(cur1).css("left", "-100%");
        });
        currentSlide = currentSlide + 1;
      }
      else{
          return false;
      };
    };

    function moveLeft(){
      if(currentSlide > 1){
          $(prev1).addClass('frontAndCenter').stop().animate({
            left: "0",
          }, 500, function() {
            $(this).removeClass("frontAndCenter");
            $(cur1).css("left", "100%");
          });
          currentSlide = currentSlide - 1
      }
      else{
          return false;
      };
    };

    switch(e.which) {
        case 37: // left
            moveLeft();
        break;

        case 39: // right
            moveRight();
        break;

        default: return;
    }
    e.preventDefault();
});

$("#arrowRight").click(function () {
    moveRight();        
});

$("#arrowLeft").click(function () {
    moveLeft();
});

});
user2478342
  • 487
  • 1
  • 6
  • 9

2 Answers2

2

Declare your functions outside the key bindings, like

var myFunction = function(e) {
  bla bla bla;
}

then call this outside function from your keydown function

(document).keydown(function(e){
    myFunction(e);
}

or call it from wherever you want.

Guilherme Lopes
  • 4,688
  • 1
  • 19
  • 42
  • 1
    +1. Furthermore, for your 2nd issue, just declare a global boolean (for ex just at the beginning of document ready function) "is_sliding" initialized to false. Then everytime you want to call the function, test if not "is_sliding" before. If not, set "is_sliding" to true, and call $.animate() method with the "complete" callback as a function(){is_sliding = false;}. See animate official doc for this callback. – Ricola3D Jun 18 '13 at 16:12
  • For variables, make functions outside of the keyevent binding that allow you to get them. – Ricola3D Jun 18 '13 at 16:13
  • Great! Thanks Ricola for that idea, makes good sense :) Guillherme- the whole thing breaks if I make all the variables global, for some reason I can't comprehend... can I still call non-global variables from outside the function, if I were to move them? – user2478342 Jun 18 '13 at 16:16
  • I try to never use global variables, instead I try to use one global object where I set all my variables like: var myApp = { version: 1.002, name: 'myTestApp', relation: 'parent' } And for functions you can add a global method or just use your values as arguments to pass from one function to another. – Guilherme Lopes Jun 18 '13 at 16:25
  • I also try to stay away from global variables/functions. The document ready function provides a new scope that your app can treat like global scope. – jcbelanger Jun 18 '13 at 16:38
  • Slowly digesting this info.. Very encouraging, thanks for all the help! – user2478342 Jun 18 '13 at 17:29
1

As for your first problem, you are right. You want to keep your event handlers simple. You will need to move your logic outside of the event handlers:

$(document).ready(function () {
   //I would recommend putting the logic in here to avoid creating global variables/functions.

   var currentSlide = 1;

   function moveLeft() { /*...reworked logic...*/ }
   function moveRight() { /*...reworked logic...*/ }

    $(document).keydown(function(e){
        switch(e.which) {
            case 37: // left
                moveLeft();
            break;

            case 39: // right
                moveRight();
            break;

            default: return;
        }
        e.preventDefault(); //*You should only really prevent default if you use the key event
    });

    $("#arrowRight").click(function () {
        moveRight();

    });

    $("#arrowLeft").click(function () {
        moveLeft();
    });
});

My second problem is that I need a way to prevent the slide functions from being called more than once while the function is still animating.

As for your second problem, I recommend you read about jquery queues. You can create your own queue that controls moving the slides back and forth (provide queueName of anything other than fx). Any left/right steps you add the queue will activate once what's on the current queue complete. If you don't want to string up multiple left/right actions, you can cancel that queue without killing all the other effects that may be running.

jcbelanger
  • 539
  • 3
  • 15