Im using a simple select list and the jquery.dropkick library to make it beautiful. Now i want to change that dropkick content after the corresponding select element has been ch
For even newer visitors. Dropkick uses the reset method...not redraw.
$("select").dropkick('reset');
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');
$('#select').html('<option>a</option>').dropkick('refresh');
For new visitors. Dropkick added redraw method.
$("select").dropkick('redraw');
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:
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
*
* © 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);