0
\$\begingroup\$

Is there a better way of toggling between different functions, on click events ? Something maybe that use "on" "off" methods or simpler alternative ?

(function($) {
        $.fn.clickToggle = function(func1, func2, func3) {
            var funcs = [func1, func2, func3];
            this.data('toggleclicked', 0);
            this.click(function() {
                var data = $(this).data();
                var tc = data.toggleclicked;
                $.proxy(funcs[tc], this)();
                data.toggleclicked = (tc + 1) % 3;
            });
            return this;
        };
    }(jQuery));

    $('#b1').clickToggle(
        function() {alert('First handler');}, 
        function() {alert('Second handler');},
        function() {alert('Third handler');}
        );
\$\endgroup\$
  • \$\begingroup\$ I think this is a good method. I think using .off() and .on() to change the handler won't work, because when the next handler is added with .on(), and the old handler returns, it will then run the next handler immediately. \$\endgroup\$ – Barmar Jan 12 '18 at 23:08
  • \$\begingroup\$ That will cause an infinite loop. \$\endgroup\$ – Barmar Jan 12 '18 at 23:09
1
\$\begingroup\$

Your general approach seems sound. But you shouldn't hard-code the number of handlers. Take the functions as a rest-arg, and use funcs.length in the modulo expression.

You can also use the argument to .data() to look up the named data element, rather than getting the whole data object.

$.fn.clickToggle = function(...funcs) {
    this.data('toggleclicked', 0);
    this.click(function() {
        var tc = $(this).data("toggleclicked");
        $.proxy(funcs[tc], this)();
        data.toggleclicked = (tc + 1) % funcs.length;
    });
    return this;
};

You might also want to special-case a single function and just bind it the normal way, and completely ignore the call if there are no functions.

$.fn.clickToggle = function(...funcs) {
    switch (funcs.length) {
    case 0:
        break;
    case 1:
        this.click(funcs[0]);
        break;
    default:
        this.data('toggleclicked', 0);
        this.click(function() {
            var tc = $(this).data("toggleclicked");
            $.proxy(funcs[tc], this)();
            $(this).data("toggleclicked", (tc + 1) % funcs.length);
        });
    }
    return this;
};
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.