2

I have 'Title' dropdown that when selected to "Dr" triggers 'Gender' dropdown to appear. On page ready I attach event handlers to change event, however there is some sort of mechanism on the page (which I don't control) that changes value on dropdown programmatically but does not trigger the change() event.

Manually invoking .change() after value is set is not a option.

How do I attach a JavaScript event handler that gets triggered when the value is changed programmatically, instead of only when it's changed via the select's UI?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265

2 Answers2

2

You can't get an event notification if code you don't control changes the selected value in the select box. You're left with the unpalatable option of polling via setInterval or a chained series of setTimeout.

I checked, and even a MutationObserver doesn't help — which isn't surprising as changing the selected item isn't mutating the DOM, but I was hoping anyway.

Polling it every 50ms or so shouldn't have any significant performance implications.

Here's a polling example, modify the interval as appropriate:

(function() {
  var s = $("#s"),
      lastValue = s.val();
  setInterval(function() {
    var value = s.val();
    if (value !== lastValue) {
      lastValue = value;
      snippet.log("The value changed to: " + value);
    }
  }, 50);
})();
snippet.log("Changing the value in a second...");
setTimeout(function() {
  snippet.log("Changing value now");
  $("#s").val("2");
  snippet.log("Done changing value");
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="s">
  <option value="1">One</option>
  <option value="2">Two</option>
  <option value="3">Three</option>
</select>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Re your comment to Amit:

knockout.js does it with observables somehow

No, it doesn't, it relies on your only modifying the select's value via the select box (which fires an event) or via KO:

var vm = {
  sval: ko.observable('one')
};
vm.sval.subscribe(function(newValue) {
  snippet.log("New value: " + newValue);
});
ko.applyBindings(vm, document.body);
snippet.log("sval is " + vm.sval() + ", changing value in select in one second");
setTimeout(function() {
  document.getElementById("s").selectedIndex = 1;
  snippet.log("Changed select, but sval is still " + vm.sval());
}, 1000);
<select id="s" data-bind="value: sval, options: ['one', 'two', 'three']"></select>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

This is modification of answer by @T.JCrowder for those who need a version that triggers .change() on first dropdown option change then shuts itself down.

(function () {
    var selector = "[id='Title']";
    var lastValue = $(selector).val();
    var timer = setInterval(function () {
        var value = $(selector).val();
        if (value !== lastValue) {
            lastValue = value;
            $(selector).change();
            clearInterval(timer);
        }
    }, 500);
})();
Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265