I have three dropdown boxes with the same class name (dd_ingredient_type_option_ar) in the test code below.
I'm trying to code a .on event to do some work when one of the dropdown boxes changes.
The code below triggers the .on event successfully and passes in the index (idx) of the dropdown that changed.
However, the .on event fires for all three dropdowns instead of just the one that changed.

The code below produces the following output when dropdown #3 is changed to the second option (Sel2 Opt2-Idx1):

alert box msg: change trigger -select idx: 2
alert box msg: ON event - idx: 2
alert box msg: type: 1

alert box msg: ON event - idx: 2
alert box msg: type: 1

alert box msg: ON event - idx: 2
alert box msg: type: 2

What am I missing in order for the .on event to just fire once on the dropdown that changed?

<html><body>
<head>
<script src='http://code.jquery.com/jquery-1.10.2.min.js'></script>
<script type='text/javascript'>

$(document).ready(function(){
	$('.dd_ingredient_type_option_ar').on('change_ingredient_type_dd', function(event, idx){
		alert('ON event - idx: ' + idx);	
		var ingredient_type = $(this).val(); //dropdown selected item
		alert('type: ' + ingredient_type);
	}); //end on change ingredient type



$('.dd_ingredient_type_option_ar').change(function(){	
	var idx = $('.dd_ingredient_type_option_ar').index(this);
	alert('change trigger - select idx: ' + idx);	
	$('.dd_ingredient_type_option_ar').trigger('change_ingredient_type_dd', [idx]); //Trigger change event for element (#dd)
});	
});

</script>
</head>

<form>
	<select class='dd_ingredient_type_option_ar'>
		<option value='1'>Sel0 Opt1-Idx0</option>
		<option value='2'>Sel0 Opt2-Idx1</option>
		<option value='3'>Sel0 Opt3-Idx2</option>
	</select>	
	<br>
	<select class='dd_ingredient_type_option_ar'>
		<option value='1'>Sel1 Opt1-Idx0</option>
		<option value='2'>Sel1 Opt2-Idx1</option>
		<option value='3'>Sel1 Opt3-Idx2</option>
	</select>	
	<br>
	<select class='dd_ingredient_type_option_ar'>
		<option value='1'>Sel2 Opt1-Idx0</option>
		<option value='2'>Sel2 Opt2-Idx1</option>
		<option value='3'>Sel2 Opt3-Idx2</option>
	</select>			
</form>

</body></html>
    cannondale;11037969 wrote:

    I'm trying to code a .on event

    On is not an event. It's how you add event handlers in jQuery.

    cannondale;11037969 wrote:

    However, the .on event fires for all three dropdowns instead of just the one that changed.

    Once again, there is no on event. A change event fires for whichever select element had its value changed. If that element has an event handler for this event, that handler is called. In your case, this event handler will, among other things:
    1. select all elements with class attribute of dd_ingredient_type_option_ar
    How many elements are matched?
    2. For all those elements, trigger an event of type "change_ingredient_type_dd"
    How many of the matched elements are listening for this event?

      johanafm,

      Thanks for your quick reply and clarification. Is there a way to tell the .on event handler which element index. of class dd_ingredient_type_option_ar, changed?
      For example,

      dd_ingredient_type_option_ar[2]

      ? I have tried a number ways to achieve this but all fail with a syntax error.

      Thanks again for your help.

        I'm no jQuery expert, but it looks to me like you have assigned one single function to any element with a matching class (dd_ingredient_type_option_ar). This means that regardless of which one you change, you are going to run one and exactly one function. This function must therefore be responsible for sniffing around and finding out which element has been changed and act accordingly. Try looking at the event object or the idx.

        Also, you have assigned a function to the change event for all of your inputs with a particular class and when any one of those inputs is changed, you have a line of code that triggers the change_ingredient_type_dd event for ALL of your inputs with matching classes:

        	$('.dd_ingredient_type_option_ar').change(function(){	
        		var idx = $('.dd_ingredient_type_option_ar').index(this);
        		alert('change trigger - select idx: ' + idx);	
        		$('.dd_ingredient_type_option_ar').trigger('change_ingredient_type_dd', [idx]); //Trigger change event for element (#dd)
        	});
        

        Try rethinking this. You correctly assign a single function to all of the inputs with that particular class. This function should be smart enough to just look at the event/idx and do what needs to be done rather than triggering some event for each of the inputs.

          Thanks for the additional information. I included an if statement in the .on event handler to only act on the element index that changed, which was passed from the change event. I'm not sure if this is the most efficient way to code this but it works as intended.

          $(document).ready(function(){
          	$('.dd_ingredient_type_option_ar').on('change_ingredient_type_dd', function(event, [B]idx[/B]){
                          [B]if($('.dd_ingredient_type_option_ar').index(this) == idx){[/B]
          		     alert('ON event - idx: ' + idx);	
          		     var ingredient_type = $(this).val(); //dropdown selected item
          		     alert('type: ' + ingredient_type);
                          }
          	}); //end on change ingredient type
          
          
          
          $('.dd_ingredient_type_option_ar').change(function(){	
          	var idx = $('.dd_ingredient_type_option_ar').index(this);
          	alert('change trigger - select idx: ' + idx);	
          	$('.dd_ingredient_type_option_ar').trigger('change_ingredient_type_dd', [idx]); //Trigger change event for element (#dd)
          });	
          });
          
          

            You are going about this the wrong way. Drop the self-defined event "change_ingredient_type_dd".

            <select class="abc"></select>
            <select class="abc"></select>
            <select class="abc"></select>
            
            jQuery(document).ready(function($) {
                $('.abc').on('change', function(e) {
                    // Do your stuff here. The change event has already called this function. Isn't once enough?
                    this == the dom node that triggered the change event;
                    e.target == same;
            
                // when you call .trigger, you are activating the event you trigger on all matching elements
                // $('div').trigger('click') - this would be the same as clicking all divs on the page. All divs with
                // click handlers assigned would then execute those click handler functions.
                // This is the ONLY reason you see three executions of your change_ingredient_type_dd even
                // Solution: do not call trigger unless you want to trigger an event.
            });
            });
            

              johanafm,

              Thanks for your reply and additional information. The .on event handler and .trigger event, in my simple example, are only part of the required solution. The actual code supports a dependent dropdown on a form. The .on event handler is actually called twice by the application. Once by the change event (of the dropdown) and again when the form is submitted (loaded) in order to repopulate the dependent dropdown on a form.

              My simple example was only to understand the interaction between .on and .trigger and how to best code the .on event handler to act on the correct element index within the class.

                7 days later

                Maybe I have read this incorrectly, but if you have an event that's attached to a set of elements, but want to be specific when one changes, you can use $(this) in your callback function. I would rewrite this and combine it into one action:

                $(document).ready(function()
                {
                	$('form').on('change', '.dd_ingredient_type_option_ar', function(event)
                        {
                            alert($(this).val());
                	}); //end on change ingredient type
                });
                

                I think you may have been confused with the syntax of the .on() function. What it does is add an event to an element (or a set of matched elements, like in this case). But in your syntax you're not adding an event in your .on() function call. You'll see in my example you're adding the 'change' event to the set of matched elements (your select boxes). When one is changed, it will alert that specific select box's value. The event is only triggered once, and you don't have to use .trigger() at all. In my experience I've only ever had to use .trigger() once, and I've done a lot of work with jQuery and complex forms, so I would surmise that it's pretty rare that you're actually going to need it.

                .trigger() works by firing an event that has already been added to an element (typically with the .on() function).

                In any case, utilizing $(this) you should be able to figure out which select box was changed. Furthermore, if you're still having trouble differentiating your elements, consider giving them IDs and then doing something like $(this).attr('id) and use that to figure out which select box was changed.

                  Bonesnap;11038263 wrote:

                  I would rewrite this and combine it into one action

                  Indeed. Original poster really should reconsider.

                  Bonesnap;11038263 wrote:

                  you're not adding an event in your .on() function call.

                  Unless I miss what code you are referring to, he is. But he has one call which is made to .change() rather than .on('change').

                  Bonesnap;11038263 wrote:

                  You'll see in my example you're adding the 'change' event to the set of matched elements (your select boxes).

                  Your example does add the event handler to the set of matched elements which is form, not "his select boxes". The "set of matched elements" always refer to whatever is matched in the call to the jQuery constructor

                  jQuery('set of matched elements').
                  

                  Whenever an element's value changes a change event fires on that element. From there, it bubbles up the parentNode chain to the DOM tree root, or until a call is made to .stopPropagation() on the event object. Whenever the event reaches an element with attached event handler(s), it (they) are called.

                  Consider this

                      <form id="frm" method="post">
                          <div id="theDiv">
                              <select id="sel">
                                  <option value="0">Select…</option>
                                  <option value="1">1</option>
                              </select>
                          </div>
                      </form>
                  
                  /* 1. currentTarget on the originalEvent event object (as unchanged by jQuery) will
                   *     match the element for which the event handler is invoked, in this case #frm.
                   * 2. this as well as e.currentTarget will however match the element #sel, because
                   *     jQuery invokes the event handler function for those elements that are in the 
                   *     parentNode chain and match the selector, as if the event was currently firing
                   *     on that element.
                   */
                  // alert: frm - sel
                  jQuery('#frm').on('change', 'select', function(e) { alert(e.originalEvent.currentTarget.id + " - " + this.id); });
                  
                  /* when you change the select element, this is the first event handler invoked, because
                   * the event bubbles from the place it originates and up the chain.
                   */
                  // alert: sel - sel
                  jQuery('#sel').on('change', function(e) { alert(e.originalEvent.currentTarget.id + " - " + this.id); });
                  
                  /* id you add an event handler for the div and uses that to .stopPropagation, the event will
                   * never reach the #frm event handler, because the event bubbling is stopped before the event
                   * gets there. That the #frm event handler would actually be called as if the event was dispatched
                   * to #sel which is before #theDiv doesn't matter.
                   */
                  // comment out this line to have the event bubbling reach the #frm element.
                  jQuery('#theDiv').on('change', function(e) { e.stopPropagation(); });
                  
                    cannondale;11037997 wrote:

                    johanafm,

                    Thanks for your quick reply and clarification. Is there a way to tell the .on event handler which element index. of class dd_ingredient_type_option_ar, changed?
                    For example,

                    dd_ingredient_type_option_ar[2]

                    ? I have tried a number ways to achieve this but all fail with a syntax error.

                    Thanks again for your help.

                    I believe you're thinking of nth-child selector. Something like:

                    jQuery('.dd_ingredient_type_option_ar:nth-child(2)')
                      Write a Reply...