How to make the jQuery toggle function in pure javascript?

4

I discovered a little time and found the toggle function very interesting using functions:

$('body').toggle(
    function(){
        alert('A')
    }, function(){
        alert('B')
    }
);

(In the example I put only 2 functions, I wanted with several)

I tried to but I could not (even looked at the code for the , but it's very complicated there.)

Explanation:

Since the toggle function will not use elements of the DOM, it could work through strings:

toggle('D', fn, fn, fn);

So every time D is mentioned in arguments[0] it will execute one function at a time from array D (D is an array of functions), if there is no D it creates a new array with functions passed to toggle() and it works normally. (In jQuery they do this with date in the elements).

    
asked by anonymous 11.02.2014 / 22:37

2 answers

8

Just keep a circular counter, which takes the next event from a list every time the element is clicked:

function toggle() {
    var eventos = arguments;
    var contador = -1;
    return function() {
        contador = (contador + 1) % eventos.length;
        eventos[contador].apply(this, arguments);
    };
}

// Exemplo de uso:
document.getElementsByTagName("body")[0].onclick = toggle(
    function() { alert("A"); }, 
    function() { alert("B"); }, 
    ...
);

Example in jsFiddle . It's good to even have an alternate implementation, since this method of .toggle is obsolete (and has already been removed in recent versions of jQuery).

Notes:

  • / li>
  • The suggested implementation is very generic and can be used for things other than the onclick event. As it passes this and arguments to each list item, it can be used in place of any function with any signature.

  • Update: As I understood after the question was edited (it's not clear to me what you want), you want the function to switch between list arguments whenever it is called with the first identical argument, is this? If it is, I believe there is no alternative but to keep your "map of functions" in a global one:

    var funcoesToggle = { };
    function toggle(qual) {
        if ( !funcoesToggle[qual] )
            funcoesToggle[qual] = { 
                contador: -1,
                funcoes: Array.prototype.slice.call(arguments, 1, arguments.length)
            };
    
        var escolhido = funcoesToggle[qual];
        escolhido.contador = (escolhido.contador + 1) % escolhido.funcoes.length;
        escolhido.funcoes[escolhido.contador]();
    }
    
    // Exemplo de uso:
    toggle("D", function() { alert("A"); }, function() { alert("B"); }, function() { alert("C"); }); // A
    toggle("D", function() { alert("A"); }, function() { alert("B"); }, function() { alert("C"); }); // B
    toggle("Ee", function() { alert("A"); }, function() { alert("B"); }, function() { alert("C"); }); // A
    toggle("D", function() { alert("A"); }, function() { alert("B"); }, function() { alert("C"); }); // C
    toggle("Ee", function() { alert("A"); }, function() { alert("B"); }, function() { alert("C"); }); // B
    

    Example in jsFiddle . Note that only the first time you use a string is that you need to pass the list of functions, in the following just call with a single argument (although this takes a little bit the purpose of the function, right?) Anyway, I strongly recommend to use the original response code - it is clearer, and does not "blend responsibilities" (ie create a list of toggle functions / use this list of functions).

        
    11.02.2014 / 22:51
    2

    In JQuery this would be it:

    $('body').toggle(
        function(){
            alert('A')
        }, function(){
            alert('B')
        }, function(){
            alert('C')
        }, function(){
            alert('D')
        }
    );
    

    That is, various functions assigned to the body of your document following an order of execution.

    But you want it in pure Javascript, I took advantage of it and also gave you a choice of order , which would in this case change the function parameter toggle() of functions A , B , C , and D you could do any order you want, or repeat some function without having to include equal functions again.

    This would be the toggle function:

    function toggle(aryFunctions,idx){
        document.getElementsByTagName("body")[0].onclick = aryFunctions[idx];
    }
    

    And to use we declare an array of functions:

    function A(){
      alert('A');
      toggle(aryFunctions,1);
    }
    function B(){
      alert('B');
      toggle(aryFunctions,2);
    }
    function C(){
      alert('C');
      toggle(aryFunctions,3);
    }
    function D(){
      alert('D');
      toggle(aryFunctions,0);
    }
    var aryFunctions = [A,B,C,D];
    
    document.body.setAttribute("onclick","toggle(aryFunctions,0)");
    

    This would execute:

      

    A,B,C,D

    It would be the correct way to circulate in order, and I'm assigning the click to the <body> tag of your html so not using DOM.

    You can change the order dynamically by changing the code of the past functions.

    You can also make it easier for you to add functions dynamically by putting them in aryFunctions which would be an Array, making your work a lot easier in this respect.

    See if I change the functions of the array to:

    function A(){
      alert('A');
      toggle(aryFunctions,3);
    }
    function B(){
      alert('B');
      toggle(aryFunctions,2);
    }
    function C(){
      alert('C');
      toggle(aryFunctions,0);
    }
    function D(){
      alert('D');
      toggle(aryFunctions,1);
    }
    var aryFunctions = [A,B,C,D];
    
    document.body.setAttribute("onclick","toggle(aryFunctions,0)");
    

    This would execute:

      

    A,D,B,C

    In this way you have enough freedom to make this toggle() as you prefer.

        
    11.02.2014 / 22:45