How to reload jquery dropkick object

徘徊边缘 提交于 2019-12-03 06:25:25

I have faced the same issue and couldn't find a solution, but finally succeeded in getting this hack work.

$select = $("#select1");
$select.removeData("dropkick");
$("#dk_container_select1").remove();

$select.append("<option>opt4</option>");
$select.append("<option>opt5</option>");

$select.dropkick();

I leveraged Diode's answer to modify the Dropkick code to make this a little cleaner:

// Reload the dropkick select widget after options have changed
// usage: $("...").dropkick('reload');
methods.reload = function () {
    var $select = $(this);
    var data = $select.data('dropkick');
    $select.removeData("dropkick");
    $("#dk_container_"+ data.id).remove();
    $select.dropkick(data.settings);
};

Add the above code right after the following snippet in dropkick.js:

methods.reset = function () {
  ...
};

Then you can use it programatically:

    $('#my-select').html("<option>new options</option>");
    $('#my-select').dropkick('reload');

For even newer visitors. Dropkick uses the reset method...not redraw.

$("select").dropkick('reset');
user1296558

I encountered the same problem, I made some patching to the jquery-dropkick-1.0.0 script to solve this problem. I added a forceSyncWithSelect method to the dropkick object.

Here's a list of changes I made:

  • add support for tag
  • add autoWidth settings to leave width to css
  • add method for open, close, forceSyncWithSelect and isDropkicked
  • keep default tabindex 0
  • add optgroup class option with the data-dkgroupclass attribute on optgroup element
  • fix forceSyncWithSelect method if value appear multiple of time, take the first occurrence only
  • toggle on click on the menu selection
  • prevent IE from closing the menu on scroll bar interaction (a blur event is launched on scroll bar interaction, this behavior is so wrong)

You may not want all those change but you can make a diff patch and take what you need (would be glad if you let the change log or add the source of it into the header, I want to propose those changes to Jamie Lottering, but I need to make a git hub account to do so.

/**
 * DropKick
 *
 * Highly customizable <select> lists
 * https://github.com/JamieLottering/DropKick
 *
 * &copy; 2011 Jamie Lottering <http://github.com/JamieLottering>
 *                        <http://twitter.com/JamieLottering>
 *
 * Patch:
 *  - 2012-03-30 godboutj, add support for <optgroup> tag
 *  - 2012-03-30 godboutj, add autoWidth settings to leave width to css
 *  - 2012-05-25 godboutj, add method for open, close, forceSyncWithSelect and isDropkicked
 *  - 2012-05-25 godboutj, keep default tabindex 0
 *  - 2012-08-09 godboutj, add optgroup class option with the data-dkgroupclass attribute on optgroup element
 *  - 2012-08-15 godboutj, fix forceSyncWithSelect method if value appear multiple of time, take the first occurrence only
 *  - 2012-09-07 godboutj, toggle on click on the menu selection
 *  - 2012-09-25 godboutj, prevent IE from closing the menu on scroll bar interaction (a blur event is launched on scroll bar interaction, this behavior is so wrong)
 */
(function ($, window, document)
{

    var ie6 = false;

    // Help prevent flashes of unstyled content
    if ($.browser.msie && $.browser.version.substr(0, 1) < 7)
    {
        ie6 = true;
    } else
    {
        document.documentElement.className = document.documentElement.className + ' dk_fouc';
    }

    var 
    // Public methods exposed to $.fn.dropkick()
    methods = {},

    // Cache every <select> element that gets dropkicked
    lists = [],

    // Convenience keys for keyboard navigation
    keyMap = {
        'left': 37,
        'up': 38,
        'right': 39,
        'down': 40,
        'enter': 13
    },

    // HTML template for the dropdowns
    dropdownTemplate = [
      '<div class="dk_container" id="dk_container_{{ id }}" tabindex="{{ tabindex }}">',
        '<a class="dk_toggle">',
          '<span class="dk_label">{{ label }}</span>',
        '</a>',
        '<div class="dk_options">',
          '<ul class="dk_options_inner">',
          '</ul>',
        '</div>',
      '</div>'
    ].join(''),

    // HTML template for dropdown options
    optionTemplate = '<li class="{{ current }}"><a data-dk-dropdown-value="{{ value }}">{{ text }}</a></li>',
    optionGroupTemplate = '<li class="dk_option_group {{ dataclass }}"><div class="dk_option_group_text">{{ text }}</div></li>',

    // Some nice default values
    defaults = {
        startSpeed: 1000,  // I recommend a high value here, I feel it makes the changes less noticeable to the user
        theme: false,
        change: false,
        autoWidth: true
    },

    // Make sure we only bind keydown on the document once
    keysBound = false
  ;

    // Called by using $('foo').dropkick();
    methods.init = function (settings)
    {
        settings = $.extend({}, defaults, settings);

        return this.each(function ()
        {
            var 
            // The current <select> element
            $select = $(this),

            // Store a reference to the originally selected <option> element
            $original = $select.find(':selected').first(),

            // Save all of the <option> and <optgroup> elements
            $options = $select.children('option,optgroup'),

            // We store lots of great stuff using jQuery data
            data = $select.data('dropkick') || {},

            // This gets applied to the 'dk_container' element
            id = $select.attr('id') || $select.attr('name'),

            // This gets updated to be equal to the longest <option> element
            width = settings.width || $select.outerWidth(),

            // Keep tabindex, even default value
            tabindex = ($select.attr('tabindex') != null && $select.attr('tabindex') != undefined) ? $select.attr('tabindex') : '',

            // The completed dk_container element
            $dk = false,

            theme
      ;

            // Dont do anything if we've already setup dropkick on this element
            if (data.id)
            {
                return $select;
            }
            else
            {
                data.settings = settings;
                data.tabindex = tabindex;
                data.id = id;
                data.$original = $original;
                data.$select = $select;
                data.value = _notBlank($select.val()) || _notBlank($original.attr('value'));
                data.label = $original.text();
                data.options = $options;
            }

            // Build the dropdown HTML
            $dk = _build(dropdownTemplate, data);

            // Make the dropdown fixed width if desired
            if (settings.autoWidth)
            {
                $dk.find('.dk_toggle').css({
                    'width': width + 'px'
                });
            }
            // Hide the <select> list and place our new one in front of it
            $select.before($dk);

            // Update the reference to $dk
            $dk = $('#dk_container_' + id).fadeIn(settings.startSpeed);

            // Save the current theme
            theme = settings.theme ? settings.theme : 'default';
            $dk.addClass('dk_theme_' + theme);
            data.theme = theme;

            // Save the updated $dk reference into our data object
            data.$dk = $dk;

            // Save the dropkick data onto the <select> element
            $select.data('dropkick', data);

            // Do the same for the dropdown, but add a few helpers
            $dk.data('dropkick', data);

            lists[lists.length] = $select;

            // Focus events
            $dk.bind('focus.dropkick', function (e)
            {
                $dk.addClass('dk_focus');
            }).bind('blur.dropkick', function (e)
            {
                // Prevent IE from closing the menu on focus loose, 
                // this make the menu close all the time when using the scroll bar
                if (!$.browser.msie)
                {
                    $dk.removeClass('dk_open');
                }
                $dk.removeClass('dk_focus');
            });

            setTimeout(function ()
            {
                $select.hide();
            }, 0);
        });
    };

    // Allows dynamic theme changes
    methods.theme = function (newTheme)
    {
        var 
      $select = $(this),
      list = $select.data('dropkick'),
      $dk = list.$dk,
      oldtheme = 'dk_theme_' + list.theme
    ;

        $dk.removeClass(oldtheme).addClass('dk_theme_' + newTheme);

        list.theme = newTheme;
    };

    // Force Value sync
    methods.forceSyncWithSelect = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk,
            $current = $dk.find("li [data-dk-dropdown-value='" + $select.val() + "']").first()
        ;
        _updateFields($current, $dk, true);
    };

    // Reset all <selects and dropdowns in our lists array
    methods.reset = function ()
    {
        for (var i = 0, l = lists.length; i < l; i++)
        {
            var 
        listData = lists[i].data('dropkick'),
        $dk = listData.$dk,
        $current = $dk.find('li').first()
      ;

            $dk.find('.dk_label').text(listData.label);
            $dk.find('.dk_options_inner').animate({ scrollTop: 0 }, 0);

            _setCurrent($current, $dk);
            _updateFields($current, $dk, true);
        }
    };

    methods.close = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        _closeDropdown($dk);
    }

    methods.open = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        _openDropdown($dk);
    }

    methods.isOpen = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        return _isDropdownOpenned($dk);
    }

    methods.toggleOpen = function ()
    {
        var 
            $select = $(this),
            $dk = $select.data('dropkick').$dk
        ;
        _toggleOpenCloseDropDown($dk);
    }

    methods.isDropkicked = function ()
    {
        var $select = $(this);
        return $select.data('dropkick') != undefined;
    }

    // Expose the plugin
    $.fn.dropkick = function (method)
    {
        if (!ie6)
        {
            if (methods[method])
            {
                return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
            } else if (typeof method === 'object' || !method)
            {
                return methods.init.apply(this, arguments);
            }
        }
    };

    // private
    function _handleKeyBoardNav(e, $dk)
    {
        var 
      code = e.keyCode,
      data = $dk.data('dropkick'),
      options = $dk.find('.dk_options'),
      open = $dk.hasClass('dk_open'),
      current = $dk.find('.dk_option_current'),
      first = options.find('li').first(),
      last = options.find('li').last(),
      next,
      prev
    ;

        switch (code)
        {
            case keyMap.enter:
                if (open)
                {
                    _updateFields(current.find('a'), $dk);
                    _closeDropdown($dk);
                } else
                {
                    _openDropdown($dk);
                }
                e.preventDefault();
                break;

            case keyMap.up:
                prev = current.prev('li');
                if (open)
                {
                    if (prev.length)
                    {
                        _setCurrent(prev, $dk);
                    } else
                    {
                        _setCurrent(last, $dk);
                    }
                } else
                {
                    _openDropdown($dk);
                }
                e.preventDefault();
                break;

            case keyMap.down:
                if (open)
                {
                    next = current.next('li').first();
                    if (next.length)
                    {
                        _setCurrent(next, $dk);
                    } else
                    {
                        _setCurrent(first, $dk);
                    }
                } else
                {
                    _openDropdown($dk);
                }
                e.preventDefault();
                break;

            default:
                break;
        }
    }

    // Update the <select> value, and the dropdown label
    function _updateFields(option, $dk, reset)
    {
        var value, label, data;

        value = option.attr('data-dk-dropdown-value');
        label = option.text();
        data = $dk.data('dropkick');

        $select = data.$select;
        $select.val(value);

        $dk.find('.dk_label').text(label);

        reset = reset || false;

        if (data.settings.change && !reset)
        {
            data.settings.change.call($select, value, label);
        }
    }

    // Set the currently selected option
    function _setCurrent($current, $dk)
    {
        $dk.find('.dk_option_current').removeClass('dk_option_current');
        $current.addClass('dk_option_current');

        _setScrollPos($dk, $current);
    }

    function _setScrollPos($dk, anchor)
    {
        var height = anchor.prevAll('li').outerHeight() * anchor.prevAll('li').length;
        $dk.find('.dk_options_inner').animate({ scrollTop: height + 'px' }, 0);
    }

    // Is dropdown openned function 
    function _isDropdownOpenned($dk)
    {
        return $dk.hasClass('dk_open');
    }

    // Close a dropdown
    function _closeDropdown($dk)
    {
        $dk.removeClass('dk_open');
    }

    // Open a dropdown
    function _openDropdown($dk)
    {
        var data = $dk.data('dropkick');
        $dk.find('.dk_options').css({ top: $dk.find('.dk_toggle').outerHeight() - 1 });
        if (!$dk.hasClass('dk_open'))
        {
            $dk.addClass('dk_open');
        }
    }

    // Toggle dropdown
    function _toggleOpenCloseDropDown($dk)
    {
        if (_isDropdownOpenned($dk))
        {
            _closeDropdown($dk);
        }
        else
        {
            _openDropdown($dk);
        }
    }

    /**
    * Turn the dropdownTemplate into a jQuery object and fill in the variables.
    */
    function _build(tpl, view)
    {
        var 
        // Template for the dropdown
            template = tpl,
        // Holder of the dropdowns options
            options = [],
            $dk
        ;

        template = template.replace('{{ id }}', view.id);
        template = template.replace('{{ label }}', view.label);
        template = template.replace('{{ tabindex }}', view.tabindex);

        if (view.options && view.options.length)
        {
            for (var i = 0, l = view.options.length; i < l; i++)
            {
                var 
                  $option = $(view.options[i]),
                  current = 'dk_option_current',
                  oTemplate = optionTemplate,
                  gTemplate = optionGroupTemplate
                ;

                if ($option.is('optgroup'))
                {
                    gTemplate = gTemplate.replace('{{ text }}', $option.attr('label'));
                    if ($option.attr('data-dkgroupclass') != undefined)
                    {
                        gTemplate = gTemplate.replace('{{ dataclass }}', $option.attr('data-dkgroupclass'));
                    }
                    // Support only one level as per W3C standard
                    $option.children('option').each(
                        function (index, element)
                        {
                            oTemplate = optionTemplate,
                            oTemplate = oTemplate.replace('{{ value }}', $(element).val());
                            oTemplate = oTemplate.replace('{{ current }}', (_notBlank($(element).val()) === view.value) ? current : '');
                            oTemplate = oTemplate.replace('{{ text }}', $(element).text());
                            gTemplate += oTemplate;
                        }
                    );

                    options[options.length] = gTemplate;
                }
                else
                {
                    oTemplate = oTemplate.replace('{{ value }}', $option.val());
                    oTemplate = oTemplate.replace('{{ current }}', (_notBlank($option.val()) === view.value) ? current : '');
                    oTemplate = oTemplate.replace('{{ text }}', $option.text());

                    options[options.length] = oTemplate;
                }
            }
        }

        $dk = $(template);
        $dk.find('.dk_options_inner').html(options.join(''));

        return $dk;
    }

    function _notBlank(text)
    {
        return ($.trim(text).length > 0) ? text : false;
    }

    $(function ()
    {

        // Handle click events on the dropdown toggler
        $('.dk_toggle').live('click', function (e)
        {
            var $dk = $(this).parents('.dk_container').first();

            _toggleOpenCloseDropDown($dk);

            if ("ontouchstart" in window)
            {
                $dk.addClass('dk_touch');
                $dk.find('.dk_options_inner').addClass('scrollable vertical');
            }

            e.preventDefault();
            return false;
        });

        // Handle click events on individual dropdown options
        $('.dk_options a').live(($.browser.msie ? 'mousedown' : 'click'), function (e)
        {
            var 
        $option = $(this),
        $dk = $option.parents('.dk_container').first(),
        data = $dk.data('dropkick')
      ;

            _closeDropdown($dk);
            _updateFields($option, $dk);
            _setCurrent($option.parent(), $dk);

            e.preventDefault();
            return false;
        });

        // Setup keyboard nav
        $(document).bind('keydown.dk_nav', function (e)
        {
            var 
            // Look for an open dropdown...
        $open = $('.dk_container.dk_open'),

            // Look for a focused dropdown
        $focused = $('.dk_container.dk_focus'),

            // Will be either $open, $focused, or null
        $dk = null
      ;

            // If we have an open dropdown, key events should get sent to that one
            if ($open.length)
            {
                $dk = $open;
            } else if ($focused.length && !$open.length)
            {
                // But if we have no open dropdowns, use the focused dropdown instead
                $dk = $focused;
            }

            if ($dk)
            {
                _handleKeyBoardNav(e, $dk);
            }
        });
    });
})(jQuery, window, document);

For new visitors. Dropkick added redraw method.

$("select").dropkick('redraw');
user3756513
$('#select').html('<option>a</option>').dropkick('refresh');
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!