Naterade
Naterade

Reputation: 2685

Jquery mobile .click firing multiple times on new page visit

So I am using Jquery mobile with great success except for one issue. Now every time a dynamic content page is navigated to by a user no matter what content displays, there is always a button at the bottom that when clicked emails the content to the address specified; works great. Now the first time a page is loaded, the click fires the event once. On the second visit its fired twice, third 3 times, etc. you get the point. I've scoured the net and implement every fix I could come across, such as using "pagecreate" instead of "pageinit", binding, unbinding, removing the div, turning off caching in the DOM but nothing works. The only success I've had is using .one() on the click but it needs to be fired if clicked again. Here is the structure. I have to .js files that load each with this to start

$( "#page" ).live( "pageinit", function() { 

Now I had the email function and other stuff in one file, but it makes it easier to separate them and I heard it does not matter. Now, here is the email function called in the pageinit

$('.eb').live('click', function() {
        var id = $('.eb').attr('id');
        var to = $('#recipient').val();
        var message = $('#email').html();

        var atpos = to.indexOf("@");
        var dotpos = to.lastIndexOf(".");
        if (atpos < 1 || dotpos < atpos + 2 || dotpos + 2 >= to.length) {
            alert('Please enter a valid email address!');
            return false;
        } 

        if(to.length == 0) {
            alert('Please enter a valid email address!');
            return false;
        } 

        $.mobile.showPageLoadingMsg();

        $.post('./services/service.email.php', { id: id, to: to, message: message}, function(data) {
            if(data.success == true) {
                $.mobile.hidePageLoadingMsg();
                alert('Your recipe has been sent!');
                $('#recipient').val('');
                return true;
            } 

            if(data.success == false) {
                if(data.fail == 1) {
                    alert('An error has occured sending your recipe. Try again soon!');
                    return false;
                }

                if(data.fail == 2) {
                    alert('Please enter a valid email address!');
                }
            }
        }, 'json');
            return false;
    }); 

Everything works flawlessly except the incremental firing of the .click on each new page. Can anyone lead me in the right direction?

Upvotes: 9

Views: 8741

Answers (4)

Mike Cheel
Mike Cheel

Reputation: 13116

If you suspect that a form (for instance a popup form) is creating multiple pages when you submit try adding data-ajax="false" to the form element of each form. This solved my problem.

Upvotes: 0

Naterade
Naterade

Reputation: 2685

I solved this by realizing the issue was with the div itself, #page. This page was loaded with dynamic content but the id never did, so somewhere along the line it cached somewhere and was fired incrementally on each new visit by one. I just added some PHP code to create a unique div id on each page load.

<?php $id = uniqid() ?>
<div id="<?php echo $id; ?>">CONTENT</div>

This solved the problem and it fires only once no matter how may page reloads there are.

Upvotes: 2

Ingemar
Ingemar

Reputation: 1658

As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers.

If you are using 1.7+ try to unbind the click event using .off() first.

$('.eb').off('click').on('click', function() {
 // ...
}); 

if you have to use .live() you can unbind the events with .die()

$('.eb').die('click').live('click', function() {
 // ...
});

or better use .delegate() and .undelegate() un the parent element:

$(document).undelegate('.eb', 'click').delegate('.eb', 'click', function() {
 // ...
});

Upvotes: 13

Jasper
Jasper

Reputation: 76003

Simply move the click event handler code outside of the pageinit event handler code like this:

$( document ).delegate( "#page", "pageinit", function() {


});
$(document).delegate('.eb', 'click', function() {
        var id = $('.eb').attr('id');
        var to = $('#recipient').val();
        var message = $('#email').html();

        var atpos = to.indexOf("@");
        var dotpos = to.lastIndexOf(".");
        if (atpos < 1 || dotpos < atpos + 2 || dotpos + 2 >= to.length) {
            alert('Please enter a valid email address!');
            return false;
        } 

        if(to.length == 0) {
            alert('Please enter a valid email address!');
            return false;
        } 

        $.mobile.showPageLoadingMsg();

        $.post('./services/service.email.php', { id: id, to: to, message: message}, function(data) {
            if(data.success == true) {
                $.mobile.hidePageLoadingMsg();
                alert('Your recipe has been sent!');
                $('#recipient').val('');
                return true;
            } 

            if(data.success == false) {
                if(data.fail == 1) {
                    alert('An error has occured sending your recipe. Try again soon!');
                    return false;
                }

                if(data.fail == 2) {
                    alert('Please enter a valid email address!');
                }
            }
        }, 'json');
            return false;
    }); 

When you use event delegation you don't want to bind inside another event handler, because each time that event handler fires you will be re-binding (and when you delegate event handlers they are delegated for the life of the DOM).

You can also use .bind() instead of .live() (this is my preferred method):

$( document ).delegate( "#page", "pageinit", function() {
    $('.eb').bind('click', ...);
});

You will notice that both of my examples change-out .live() for .delegate() as it performs slightly faster even when delegating from the document element. .delegate()s real strength is that you can choose the root element rather than having to bind to the document element: http://api.jquery.com/delegate

Upvotes: 10

Related Questions