简体   繁体   中英

jQuery, associative array and binding events

I would like to bind the same event to 3 checkboxes but with a different target each time:

  var checkboxes = {
    'selector1' : 'target1',
    'selector2' : 'target2',
    'selector3' : 'target3',
  };

  for (selector in checkboxes) {
    var target = checkboxes[selector];

    if (jQuery(selector).is(':checked')) {
      jQuery(target).show();
    }
    else {
      jQuery(target).hide();
    }

    jQuery(selector).bind('change', function() {
      if ($(this).is(':checked')) {
        jQuery(target).show();
      }
      else {
        jQuery(target).hide();
      }
    });
  };

But it doesn't work: on "change", the 3 selectors show/hide the 3rd target.

That's because the code in the event handler will use the variable target , not the value of the variable as it was when the event handler was created. When the event hander runs, the variable will contain the last value used in the loop.

Use an anonymous function to create a closure, that captures the value of the variable:

for (selector in checkboxes) {
  var target = checkboxes[selector];

  if (jQuery(selector).is(':checked')) {
    jQuery(target).show();
  } else {
    jQuery(target).hide();
  }

  (function(target){

    jQuery(selector).bind('change', function() {
      if ($(this).is(':checked')) {
        jQuery(target).show();
      } else {
        jQuery(target).hide();
      }
    });

  })(target);

};

Side note: You can use the toggle method to make the code simpler:

for (selector in checkboxes) {
  var target = checkboxes[selector];

  jQuery(target).toggle(jQuery(selector).is(':checked'));

  (function(target){

    jQuery(selector).bind('change', function() {
      jQuery(target).toggle($(this).is(':checked'));
    });

  })(target);

};

It doesn't work because target isn't scoped inside of a function. Blocks DO NOT provide scope in javascript.

But I've reduced it down for you and hopefully this will work out:

$.each(checkboxes, function(selector, target) {
   $(selector).change(function () {
       $(target).toggle($(selector).is(':checked'));
   }).trigger('change');
});

target scope is the problem !

You could have simpler code:

  • use data for the handler
  • use .toggle(condition)

     $.each(checkboxes, function(selector, target) { $(selector).on('change', {target:target}, function (evt) { $(evt.data.target).toggle($(this).is(':checked')); }).change(); }); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM