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\$
2
  • \$\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, 2018 at 23:08
  • \$\begingroup\$ That will cause an infinite loop. \$\endgroup\$
    – Barmar
    Jan 12, 2018 at 23:09

1 Answer 1

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 and acknowledge you have read our privacy policy.

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