0

I built a cascading dropdown in jquery, modified from a few examples. I added a feature to let the user "back up" and reselect an earlier dropdown. This reloads the next dropdown, and clears and disables the subsequent ones.

http://jsfiddle.net/goodeye/gA6GZ/

The problem is after the first time through, the select elements' change events are bound, so I think reloading new values is causing the later change events to fire.

I separated out the .change() bind, instead of chaining it. I previously had it chained before loading the select options. This helped the first time through, but not subsequent times.

For this problem, I'm specifically looking for a good approach to this sequence:

  • avoid change()
  • update the dropdowns
  • set up change()

This question: Best way to remove an event handler in jQuery? has unbind() as the main answer, then a subsequent answer to use live(). The live() approach uses a class which is slightly confusing me, and didn't get as many votes.

To reproduce:
Select step 1, see step 2 fire.
Select step 2, see step 3 fire.
Select step 1 again, see step 2 fire.
then the trouble starts:
Select step 2, see step 3 fire twice.
Select step 3, see step 4 fire three times.
Select step 1 again, see step 2 fire twice.
etc.
It even gets worse; I'll see step 3 fire five times.

Some details:

In the real code, these load from a json ajax call. I removed that from the example, and added hard-coded options to simulate it, scoping this to just the event issue.

This starts out server-side, so the first dropdown is already "in" the html. The next three are loaded from (simulated) json calls.

These use classes for identification, because the real page has more than one set of these dropdowns. The code uses $(this) to be careful to work within the one set that was selected.

There is also a feature to 'auto select' if there's only one option, and move on to the next one. This code is in there, but the simulated examples all have more than one option, to avoid this issue for this question.

Thanks in advance for your ideas!

Community
  • 1
  • 1
goodeye
  • 2,319
  • 5
  • 33
  • 66
  • Now I'm not sure if it's updating the options that's causing the multiple calls, or if it's because I'm calling change() more than once; each time through the sequence. Does calling change() again cause it to fire more than once? ... or maybe that's another question. – goodeye Jul 17 '11 at 22:58

2 Answers2

0

What you can do is use jQuery to inspect all the bound change events on the element, keep them in an "offline" array, unbind them, do your stuff and them rebind them.

To inspect all bound change events you can use:

var changeEvents = $(element).data("events").change;
jQuery.each(changeEvents, function(key, handlerObj) {
    alert(handlerObj.handler) // alerts "function() { alert('changed!') }"
    // also available: handlerObj.type, handlerObj.namespace
})
Variant
  • 16,291
  • 4
  • 37
  • 64
  • That's a handy tidbit. In this case, I already know what I'm binding, so I don't need to discover it. – goodeye Jul 18 '11 at 15:21
0

Well, I ran out of time and had to solve it. It was simply to set up the binding once - that's all there was to it. So this solves the problem, and didn't need to unbind/rebind, or use live() in this case.

Do the following code once up front. It binds the dropdowns once, and disables the 2nd, 3rd, 4th until the cascading starts from calling the first one. So the binding is done once, then disabled true/false is toggled.

$('.ddStep1').change(getStep2);
$('.ddStep2').change(getStep3).attr('disabled', true);
$('.ddStep3').change(getStep4).attr('disabled', true);
$('.ddStep4').attr('disabled', true);

(In this application, the last dropdown doesn't have a change event; there's a separate submit button after the 4th is selected.)

The problem was the multiple calls to create the binding - this is a one-time thing, so calling it more than once was attaching multiple calls on the change event.

Adding and removing the select options wasn't calling the change event.

Answering the original question about temporarily disabling the event (albeit not the solution for my problem), I did get to understand using live() from this answer, and think that would be the way to go: Best way to remove an event handler in jQuery? The other answer to that question using namespaces looks decent too.

Community
  • 1
  • 1
goodeye
  • 2,319
  • 5
  • 33
  • 66