Drew
Drew

Reputation: 4373

Jquery BIND works but ON does not

I have edited my original code example to include the "right way" I should have done it

I am working on a jquery mobile project and I have noticed that if I use ON to bind a click it will work the first time the page loads but if I return to the page then I get another bind each time I return. If I use BIND then I only get one regardless of how many times I leave the page and return.

I am fine with using BIND but I know it is going away in the future so I would like to know why ON isn't working?

I am using jquery 1.9.1 and jquery mobile 1.3.1

This code is in the head section of every page:

 <link rel="stylesheet" href="resources/js/jquery.mobile-1.3.1.min.css" />
 <script src="resources/js/jquery-1.9.1.min.js"></script>
 <script type="text/javascript">
    console.log('head javascript - before JQM is loaded');


    // EDITED: Don't put JQM events inside .ready()
    //$(function() {


            // *** EDITED - THIS IS CORRECT WAY TO USE .on() IN THIS CASE ****
            $(document).on("pageinit", "#page_login", function() {
                console.log('#page_login page - pageinit event -- (only once for THIS page)');
                $('#loginformSubmit').on('click', login_form_click_handler);
            });


            // *** THIS ONE WORKS ****
            $(document).on("pageinit", "#page_login", function() {
                console.log('#page_login page - pageinit event -- (only once for THIS page)');
                $('#loginformSubmit').bind('click', login_form_click_handler);
            });



           // *** BUT, if I replace the section above with this
           //          then the login_form_click_handler() function
           //          will get executed N+1 times, where N = number
           //          of times I have viewed the page. 

           $(document).on("pageinit", "#page_login", function() {
                console.log('#page_login page - pageinit event -- (only once for THIS page)');               
                /* EDITED NOTE:  This doesn't work correctly because JQM maintains
                                 a single 'document'  so each time this event is 
                                 fired (initial browse and subsequent visits if 
                                 page is not in jqm cache) I was binding another
                                 click event to the document which already had one
                                 (or more) of the same.  */
                $(document).on('click', '#loginformSubmit', function(e){                 
                     login_form_click_handler(e);
                });
           });


    //});


    <script src="resources/js/jquery.mobile-1.3.1.min.js"></script>

This is the body section of the #page_login page

<div data-role="page" id="page_login" data-theme="b" data-content-theme="b">


<div data-role="header">
    <h1>AV Login</h1>
    <a href="resources/dialogs/login_help.htm" data-icon="info" data-iconpos="right" data-theme="b" data-rel="dialog" class="ui-btn-right">Help</a>
</div>

<div data-role="content">

<form id='loginform' class="validate" action="resources/processors/login.php" method="post">

<div data-role="popup" id="invalid_login" data-transition="pop" class="ui-content" data-theme="e" data-overlay-theme="a" style="max-width:350px;">
<a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-btn-right">Close</a>
Invalid username or password
</div>

<div data-role="popup" id="login_processor_error" data-transition="pop" class="ui-content" data-theme="e" data-overlay-theme="a" style="max-width:350px;">
<a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-btn-right">Close</a>
<div id="login_processor_error_content"></div>
</div>

<ul data-role="listview" data-inset="true">


<li data-role="fieldcontain">
<label for="username">Username:</label>
<input type="text" name="username" id="username" data-mini="true"  class="required" />
</li>


<li data-role="fieldcontain">
<label for="password">Password:</label>
<input type="password" name="password" id="password" data-mini="true" class="required" />
</li>

</ul>

<a id="loginformSubmit" href="" data-role="button" data-mini="true">Login</a>
</form>


<script type="text/javascript">
function login_form_click_handler(e){
    console.log('login_form_click_handler');
    e.preventDefault(); 
            // EDIT NOTE:  'this' is the #loginformSubmit element
            //        can setup your own var to use, such as:  var $this = $('#loginform');

             // .. do form validation, submission, etc ..
}
</script>

</div>

</div>

Upvotes: 0

Views: 188

Answers (2)

awbergs
awbergs

Reputation: 942

In jQuery mobile the document normally stays the same through page transitions. The reason I point that out is that any time you are adding an event listener to an element (the document in this case) it is adding to a collection of any other event listeners already added. This is regardless of if you use .bind or .on. So every time you call .on('click', '#loginformSubmit', ... you are adding more listeners to that document click event.

If you change your event binding to look like this:

$('#loginformSubmit').on('click', login_form_click_handler);

You will see the same results as using .bind in the same fashion.

When you use the .on event binding syntax as you are, it's adding the event listener to the $(document) but will only fire your function when it bubbles up to the scoped selector #loginformSubmit.

jQuery .on documentation

Upvotes: 1

Kevin B
Kevin B

Reputation: 95028

Your usage of .bind and .on are very different. The way you're using .on is with event delegation, and event delegation can be interrupted by events that stop propagation.

$('#loginformSubmit').bind('click', login_form_click_handler);

is equivalent to

$('#loginformSubmit').on('click', login_form_click_handler);

Though, the real problem is that you're losing this due to how you're calling the function. The following would probably work too, assuming the propagation isn't being stopped.

$(document).on('click', '#loginformSubmit', login_form_click_handler);

however it could result in double binding since it's bound to the document and hence will never go away unless you unbind it.

Upvotes: 1

Related Questions