Q:

Bootstrap Multiselect plugin and disabling/enabling checkboxes on the change event

I'm using Bootstrap Multiselect to show a list of years where the maximum count of selected years can be 4. Ie. if 4 years have been selected, disable all the unselected years ; if a year has been unselected to make the count 3, enable all the years again.
(The latest commit on that plugin's project was to add an enable/disable feature but I don't think that's for individual select elements - https://github.com/davidstutz/bootstrap-multiselect/issues/171)
My HTML:
<select id="slYears" class="multiselect" multiple="multiple">
    <option value="1" disabled="disabled">2009</option>
    <option value="2" selected="selected">2010</option>
    <option value="3" selected="selected">2011</option>
    <option value="4" selected="selected">2012</option>
    <option value="5" selected="selected">2013</option>
</select>

My JavaScript (first attempt):
$('#slYears').change(function () {
    var arr = $(this).val().toString().split(',');
    if (arr.length >= 4) {
        $('#slYears option').each(function () {
            if (!$(this).is(':selected')) {
                $(this).prop('disabled', true);
            }
        });
    }
    else {
        $('#slYears option').each(function () {
            $(this).prop('disabled', false);
        });
    }
});

Then I tried using some of the plugin's methods and examples. I tried using the 'select all' example to enable all, I tried using the 'onchange' event, but none of it works.
Here is the jsfiddle: http://jsfiddle.net/389Af/1/ (note I pasted the plugin JS before the above JS)

A:

OK I came up with a solution. I added a demo to the current master branch of the plugin. See here: http://davidstutz.github.io/bootstrap-multiselect/#further-examples. The code looks as follows. In this code the select has the ID example37:
$('#example37').multiselect({
  onChange: function(option, checked) {
    // Get selected options.
    var selectedOptions = $('#example37 option:selected');

      if (selectedOptions.length >= 4) {
        // Disable all other checkboxes.
        var nonSelectedOptions = $('#example37 option').filter(function() {
          return !$(this).is(':selected');
        });

        var dropdown = $('#example37').siblings('.multiselect-container');
        nonSelectedOptions.each(function() {
          var input = $('input[value="' + $(this).val() + '"]');
          input.prop('disabled', true);
          input.parent('li').addClass('disabled');
        });
      }
      else {
        // Enable all checkboxes.
        var dropdown = $('#example37').siblings('.multiselect-container');
        $('#example37 option').each(function() {
          var input = $('input[value="' + $(this).val() + '"]');
          input.prop('disabled', false);
          input.parent('li').addClass('disabled');
        });
      }
    }
  });

Some explanation: selectedOptions is an array of the currently selected options. If 4 or more options are selected all other checkboxes are disabled (the options within the invisible select are not disabled). If less than 4 options are selected all checkboxes are enabled again.

A:

David's answer helped me a lot. Thanks for that.
I changed his code to be more generic/applicable for any multiselect.
It requires that the select-element data value "max" is set.
<select ... data-max="5"/>
onChange: function (element) {
    var me = $(element), // is an <option/>
        parent = me.parent(),// is a <select/>
        max = parent.data('max'), // defined on <select/>
        options, // will contain all <option/> within <select/>
        selected, // will contain all <option(::selected)/> within <select/>
        multiselect; // will contain the generated ".multiselect-container"

    if (!max) { // don't have a max setting so ignore the rest
        return;
    }

    // get all options
    options = me.parent().find('option');

    // get selected options
    selected = options.filter(function () {
        return $(this).is(':selected');
    });

    // get the generated multiselect container
    multiselect = parent.siblings('.btn-group').find('.multiselect-container');

    // check if max amount of selected options has been met
    if (selected.length === max) {
        // max is met so disable all other checkboxes.

        options.filter(function () {
            return !$(this).is(':selected');
        }).each(function () {
            multiselect.find('input[value="' + $(this).val() + '"]')
                .prop('disabled', true)
                .parents('li').addClass('disabled');
        });

    } else {
        // max is not yet met so enable all disabled checkboxes.

        options.each(function () {
            multiselect.find('input[value="' + $(this).val() + '"]')
                .prop('disabled', false)
                .parents('li').removeClass('disabled');
        });
    }
}

It would be nice to have something like a "max-allowed" option to be part of the component specification.. ;-)

