2

My HTML (not dynamic) looks like this:

<select id="domain" class="marketplace">
  <option>United States</option>
  ...
</select>

This works:

$("#domain").on("change", function() {
  $("#domain").attr("disabled", "disabled");
  /* do ajaxy stuff */
  $("#domain").removeAttr("disabled");
});
$("select.marketplace").on("change", function() { /* do some general stuff */});

This does not:

$("#domain").on("change", function() {
  $("#domain").attr("disabled", "disabled");
  /* do ajaxy stuff */
  $("#domain").removeAttr("disabled");
});
$(document).on("change", "select.marketplace", function() { /* do some general stuff */});

Removing the $("#domain").attr("disabled", "disabled"); call restores the functionality of the $(document).on() delegation, so it appears events do not bubble when an element is disabled, regardless of how the event is triggered (i.e. neither by .trigger nor .triggerHandler nor by user interaction). However, I do not understand why, as neither handler returns anything or makes any calls to prevent event propagation, and the jQuery documentation makes no mention of the "disabled" attribute having any effect on propagation. What am I missing here?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Craig Kovatch
  • 327
  • 1
  • 3
  • 14
  • You're probably getting an exception in the first handler. Please show us the complete code. – SLaks Apr 11 '12 at 01:49
  • ... didn't you *just* ask this? – Ry- Apr 11 '12 at 01:51
  • It would appear `$("#domain").attr("disabled", "disabled");` in the "specific" handler is the source of the problem. Are events not bubbled for "disabled" elements? – Craig Kovatch Apr 11 '12 at 01:54
  • @minitech Upon further investigation I discovered that my original question was insufficient to describe the failure case (i.e. everyone said "works for me"), so I re-created it to fill in the sufficient context. Was that improper etiquette? – Craig Kovatch Apr 11 '12 at 01:55
  • 1
    @kobachi: No, I suppose you deleted it? That's fine then. Normally, though, you can just edit the details into the original question - just for future reference. – Ry- Apr 11 '12 at 01:59
  • Please post your actual code. –  Apr 11 '12 at 02:12
  • I've re-framed the question, posted the bits of code that seem to be the culprit. Unfortunately I cannot post the actual code as it's internal to my company. – Craig Kovatch Apr 11 '12 at 02:15
  • I'm guessing @Gothdo really wanted to know the answer to this old question, unfortunately I don't think anyone else really cares about issues that used to be present in jQuery 1.7 and below ? – adeneo Mar 05 '16 at 04:59
  • @adeneo Actually I had a bit different problem: I wanted to use delegated click event listener on a disabled element and I didn't want to ask new question, because I thought it would be a duplicate. This is not possible in newer jQuery versions too. And I don't think that nobody cares about jQuery 1.7, because for example SE uses jQuery 1.7.1. – Michał Perłakowski Mar 05 '16 at 10:26
  • @Gothdo - disabled elements do not fire mouse events, so that's not really possible. However the faulty code in this question now works in jQuery 1.8+ – adeneo Mar 05 '16 at 13:03
  • @adeneo Yes, but in my case the element gets disabled on click by jQuery event listener over which I have no control, and I want to capture the event before the element gets disabled. See [this JS Fiddle](https://jsfiddle.net/Gothdo/rmyjjfvp/) -- the jQuery event handler doesn't work, but native DOM works. – Michał Perłakowski Mar 05 '16 at 13:40
  • 1
    @Gothdo - Just use the `mousedown` event – adeneo Mar 05 '16 at 15:35
  • @adeneo Thanks, I combined it with `mouseup`, and [it works](https://jsfiddle.net/Gothdo/rmyjjfvp/1/) exactly as `click`. – Michał Perłakowski Mar 05 '16 at 15:57

2 Answers2

2

Just to reproduce your problem I created the following snippet (the button Click Me is used to trigger the change event, just to have a full demo):

$(document).on("change", "select.marketplace", function (e) {
  $('#result').append('<p>$(document).on("change", "select.marketplace", function (e) {: This does not work!<p/>');
});
$(function () {
  $("#domain").on("change", function () {
    $("#domain").attr("disabled", "disabled");
    /* do ajaxy stuff */
    //$("#domain").removeAttr("disabled");
  });
  $("select.marketplace").on("change", function (e) {
    $('#result').append('<p>$("select.marketplace").on("change", function (e) {: This work!<p/>');
  });
  $('#btn').on('click', function (e) {
    $('#domain').trigger('change');
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>

<button id="btn">Click Me</button>
<select id="domain" class="marketplace">
    <option>United States</option>
    <option>United States</option>
    <option>United States</option>
    <option>United States</option>
</select>
<div id="result"></div>

I commented the removeAttr disabled on domain change event to reproduce the error.

With jQuery 1.7 the document on change does not work like you immagine.

Let's now change the document on change with a generic document on and let's filter the event targets:

$(document).on("change", function (e) {
   if ($(e.target).is('select.marketplace')) {
      $('#result').append('<p>$(document).on("change", function (e) {: This works!<p/>');
   }
});
$(function () {
  $("#domain").on("change", function () {
    $("#domain").attr("disabled", "disabled");
    /* do ajaxy stuff */
    //$("#domain").removeAttr("disabled");
  });
  $("select.marketplace").on("change", function (e) {
    $('#result').append('<p>$("select.marketplace").on("change", function (e) {: This work!<p/>');
  });
  $('#btn').on('click', function (e) {
    $('#domain').trigger('change');
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>



<button id="btn">Click Me</button>
<select id="domain" class="marketplace">
    <option>United States</option>
    <option>United States</option>
    <option>United States</option>
    <option>United States</option>
</select>
<div id="result"></div>

Now you see a different behaviour, exactly what you are looking for.

Of course it's not the best solution, it's only a way to solve the problem.

I wait for other ideas because my solution is only a workaround.

If you are interested to get more info, you may take a look to the jQuery

dispatch: function( event ) {

in the source code jQuery 1.7 paying attention to "disabled" word.

gaetanoM
  • 41,594
  • 6
  • 42
  • 61
  • Are you saying using .bind for event delegation instead of .on is fixing the problem, only in 1.7? because that syntax of bind doesn't exist. what' you're actually doing is basically identical to `$(document).bind("change",function () {...})` meaning it'l catch all change events, not just the ones from the target elements. – Kevin B Mar 02 '16 at 20:10
  • sorry, i updated the comment. basically, i don't think the code is doing what you think it is doing. – Kevin B Mar 02 '16 at 20:13
  • See here: https://jsfiddle.net/atcwen6m/ changing the second select is incorrectly triggering the event that should only be happening on the first. – Kevin B Mar 02 '16 at 20:16
  • the .delegate() method would be the right alternative, but, it's just going to end up calling .on internally anyway, so it won't fix the problem. – Kevin B Mar 02 '16 at 20:19
-1

Have you tried namespacing the events like so:

$(document).ready(function() {
  $("#domain").on("change.eventOne", function() { /* do some specific stuff */ });
  $(document).on("change.eventTwo", "select.marketplace", function() { /* do some general stuff */ });
});

You may also want to try attaching from the body. I have had better luck with this:

$(document).ready(function() {
  $("#domain").on("change.eventOne", function() { /* do some specific stuff */ });
  $('body').on("change.eventTwo", "select.marketplace", function() { /* do some general stuff */ });
});

Here is a fiddle of the on event clearly working. Unless I am not understanding what "working" actually means to the OP.

https://jsfiddle.net/szcjszkz/1/

xcopy
  • 2,248
  • 18
  • 24
  • I have tried attaching from the body without success. As I commented a moment ago, it would appear a call to `$("#domain").attr("disabled", "disabled")` in the `#domain` handler is the source of my trouble, although I do not see anything in the jQuery documentation to explain why. – Craig Kovatch Apr 11 '12 at 01:57
  • Doesn't work for me. Post a working code snippet and I'll reverse my downvote. – Michał Perłakowski Feb 28 '16 at 22:09
  • It would help to know what is not working for you. My interpretation of the original poster's problem was that the $(document).on("change" ... event was not firing. – xcopy Feb 29 '16 at 17:52
  • Sorry, I removed jQuery version number (1.7) from the question, because I thought it's not relevant, but it turned out it was. This works fine in jQuery 1.8+, but does not with 1.7. – Michał Perłakowski Mar 01 '16 at 03:04
  • Yes, but OP is calling `.removeAttr` in an AJAX callback, and in this code it's called immediately. – Michał Perłakowski Mar 02 '16 at 13:19
  • @Gothdo Right. I think that this question was very poorly worded. It would be much clearer if you, or the op describe exactly what you are trying to do here. For example, in the op question, he is essentially trying to get a change event to fire on a disabled select. Why disable it then? – xcopy Mar 02 '16 at 16:49