JavaScript/jQuery dropdownlist change event with c

2019-07-18 22:05发布

问题:

In my sample code, I have 2 dropdownlists (but in the real code the number varies because the dropdownlists are created dynamically) and what I wanted to do is to count how many dropdownlists are selected with a non-zero value. I used closure to keep track of the total number of dropdownlists with non-zero selected value. I was successful in doing that (refer to http://jsfiddle.net/annelagang/scxNp/9/).

Old/Working Code

$("select[id*='ComboBox']").each(          
          function() {              
              $(this).change(
                  function() {
                      compute(this);
              });         
      });

    var compute = (function () {
    var total = 11; 
    var selectedDdl = [];

    $("#total").text(total);     
    return function (ctrl) {
         var id = $(ctrl).attr("id");
         var ddlMeal = document.getElementById(id);
         var found = jQuery.inArray(id, selectedDdl);

        if (ddlMeal.options[ddlMeal.selectedIndex].value != 0){
             if(found == -1){
                 total += 1; 
                 selectedDdl.push(id);        
             } 
             else{
                 total = total;
             }
         }
         else {
             total -= 1;
             var valueToRemove = id;
             selectedDdl = $.grep(selectedDdl, function(val) 
                                      { return val != valueToRemove; });
         }        

         $("#total").text(total); 
    };     
}());

Note: I initialized the total variable with 11 because as I mentioned in the real code I can have more than 2 dropdownlists and I just wanted to test if my code will work on values more than 2.

When I tried transferring the closure inside the .change() event, it no longer works (see http://jsfiddle.net/annelagang/scxNp/12/) Could somebody please help me figure this one out? I've been doing this code for a few days now and it's getting quite frustrating.

New/Non-working code:

$("select[id*='ComboBox']").each(          
          function() {              
              $(this).change(
                  function() {
                     (function () {
                var total = 11; 
                var selectedDdl = [];

                $("#total").text(total);     
                return function (ctrl) {
                     var id = $(ctrl).attr("id");
                     var ddlMeal = document.getElementById(id);
                     var found = jQuery.inArray(id, selectedDdl);

                     if (ddlMeal.options[ddlMeal.selectedIndex].value != 0){
                         if(found == -1){
                             total += 1; 
                             selectedDdl.push(id);        
                         } 
                         else{
                             total = total;
                         }
                     }
                     else {
                         total -= 1;
                         var valueToRemove = id;
                         selectedDdl = $.grep(selectedDdl, function(val) 
                                           { return val != valueToRemove; });
                         }        
                    $("#total").text(total); 
                };     
        }());
          });         
      });

Thanks in advance.

P.S. I'm also open to less messier solutions.

回答1:

I believe this should work:

$("select[id*='ComboBox']").change(function() {
    $("#total").text($("select[id*='ComboBox'][value!=0]").length);
});

http://jsfiddle.net/scxNp/15/



回答2:

Problem

You are returning function from self-executing anonymous function, but do not assing the returned value anywhere.

Simplifying your code, it looks like that:

/* some code here */
$(this).click(function(){
    /** The following function is executed, returns result, but the
     *  result (a function) is not assigned to anything, nor returned
     */
    (function(){
        /* some code here */
        return function(ctrl){
            /* some code here */
        };
    }());
});
/* some code here */

Solution

Generally your code is very unreadable, you should improve it for your own good (and to avoid such problems). The problem above can be quickly fixed by passing parameter to the function that returns a function (but did not call it). Solution is here: jsfiddle.net/scxNp/13/

Solution: explanation

What I did was simple - I spotted that you pass this to the function from the first (working) example, but you do not even execute this function in the second (incorrect) example. The solution, simplified, looks like this:

/* some code here */
$(this).click(function(){
    /** Now the result of the following function is also executed, with
     *  parameter passed as in your working example
     */
    (function(){
        /* some code here */
        return function(ctrl){
            /* some code here */
        };
    }())(this);
});
/* some code here */

Hope this makes sense :)

Ps. I have also updated my first code snippet so the changes should be easily spotted :)

Ps.2. This is only a quickfix and - as mentioned above - there is a lot to be made to make your code readable. Also every function works as closure, so do not overuse self-executing (function(){/* your code */})(); that you do not assign to anything (it is useful, but one time for one script should be enough). Instead use the existing closures.



回答3:

how about this?

html:

<select id="ComboBox1" class="howMany">
<option value="0">Value 0</option>
<option value="1">Value 1</option>
<option value="2">Value 2</option>
<option value="3">Value 3</option>
</select>

<select id="ComboBox2" class="howMany">
<option value="0">Value 0</option>
<option value="1">Value 1</option>
<option value="2">Value 2</option>
<option value="3">Value 3</option>
</select>

<div id="total"></div>

script:

$(".howMany").change(
function ()
{
    var nonZero = 0;
    $(".howMany").each(
        function ()
        {
            if ($(this).val() != '0')
                ++nonZero;
        }           
    );
    $("#total").text('There are '+nonZero+' options selected');       
}
);