Diego de Oliveira
Diego de Oliveira

Reputation: 681

jQuery Click event triggers more times on every window resize

People!

This is the first time I come here to ask something, so far, always when I had a problem, I could find a good answer here. So, in first place, thanks for this amazing community!

Now let's go to the problem:

I'm doing a responsive menu that check the window.resize event and, when it fits the minimum browser width, a click function for a button is allowed. If the browser width is greater, then the click function is unbound. I need to do this because the same element that is the button on the mobile version, is a visual element on the desktop version.

The problem is that, with the code that I have now, when the page is loaded, the click function works fine. But, if I resize the browser and click on the element again, it triggers more than once the state, sometimes leaving the impression that the function isn't triggered. And, if I resize the browser again, it triggers the click function more than the last time I clicked. Really annoying.

To help understand what is happening, I've made a simple example. Here's is the simple code (just to check the click function issue):

HTML:

<ul>
    <li><span class="sub-toggle">Testing 01</span></li>
    <li><span class="sub-toggle">Testing 02</span></li>
    <li><span class="sub-toggle">Testing 03</span></li>
</ul>

CSS:

.sub-toggle{
    display:block;
    padding: 20px;
}

.sub-toggle.active{
    background-color: #ffcc00;
    color: #fff;
}

Javascript (jQuery):

jQuery(function($){

    var i = 1;

    // check if browser size is compatible with click event
    onResize = function() {

        // if browser size is ok, do the click function
        if($(window).width() <= 480){

            // click function
            $('.sub-toggle').click(function(){

                alert('click');

                if($(this).hasClass('active')){
                    alert('active');
                    $(this).removeClass('active');
                } else {
                    $(this).addClass('active');
                }

            });     

        } else{
            // if browser size is greater than expected, unbind the click function
            $('.sub-toggle').removeClass('active').unbind('click');
        }

        // just checking how many times the resize function is triggered 
        console.log('resize: '+ i);
        i++;

    }

    $(document).ready(onResize);

    var timer;

    $(window).bind('resize', function(){
        timer && clearTimeout(timer);
        timer = setTimeout(onResize, 500);
    });

});

(Edited to remove some unnecessary code)

If you want to see it in action, I've made a Fiddle (try resize the output frame to see it working): http://jsfiddle.net/C7ppv/1/

Maybe I've missing something really stupid, since I don't have a huge knowledge in JavaScript. But what I want to do is just trigger the click event once, even if multiple resizes.

I hope I could explain well my problem. I've searched and didn't found a solution for this issue (or maybe I just didn't know really well what to look for).

Any help would be appreciated!

Upvotes: 4

Views: 8905

Answers (3)

bfavaretto
bfavaretto

Reputation: 71918

The resize event is triggered multiple times during resizing, and each time you're binding a new click handler. My suggestion: bind only once, from outside the resize handler, and set a flag while resizing to let the click handler know if it should do something or not.

Then you won't even need to defer the handling of resize with setTimeout as you're doing.

DEMO

jQuery(function($){

    var i = 1;

    // flag to allow clicking
    var clickAllowed = true;

    // click function
    $('.sub-toggle').click(function(){
        if(clickAllowed) {
            alert('click');

            if($(this).hasClass('active')){
                alert('active');
                $(this).removeClass('active');
            } else {
                $(this).addClass('active');
            }
        }
    }); 

    // check if browser size is compatible with click event
    onResize = function() {

        //if browser size is ok, do the click function
        if($(window).width() <= 480){
            clickAllowed = true;
        }
        else{
            // if browser size is greater than expected, disallow clicking
            clickAllowed = false;

        }

        // just checking how many times the resize function is triggered 
        console.log('resize: '+ i);
        i++;

    }

    $(document).ready(onResize);

    var timer;
    $(window).bind('resize', onResize);
});

Upvotes: 5

Ruben Infante
Ruben Infante

Reputation: 3135

Your code currently binds a new click events every time the method onResize is called and the window width is less than or equal to 480px.

Simply unbind any existing click events on the .sub-toggle element before binding a new one.

$('.sub-toggle').unbind('click').click(function() {
    ...
});

DEMO

Upvotes: 7

pdoherty926
pdoherty926

Reputation: 10359

Move $('.sub-toggle').click(function(){...} outside the onResize event handler and move if($(window).width() <= 480){...} into the click handler.

Upvotes: 2

Related Questions