I am using select2 v4 to render almost 2k+ item, I don’t want to build option at page load. So what I have done is to load data on select2: open event. But the problem I am facing is when data is attached to select2, the controls gets reload/refresh.
Here is the code(select2 with knockout):
<select data-bind="select2:{
dataSource: data,
placeholder: 'Search...'
}"></select>
js file :
define('binding-handlers/select2', ['jquery', 'knockout', 'utils', 'select2', 'jquerybrowser'],
function($, ko, utils, select2, jqueryBrowser) {
var matcher = function(params, data) {
//make searchTerm available for sort function
if (!params.term || $.trim(params.term) === '' || data.text.toLowerCase().indexOf(params.term.toLowerCase()) > -1) {
data.searchTerm = params.term;
return data;
}
return null;
};
var sorter = function(results) {
var searchTerm = (results && results.length > 0) ? results[0].searchTerm : false;
if (!searchTerm) {
$('.select2-results').hide();
} else {
$('.select2-results').show();
}
if (searchTerm) {
var resultsStartingWith = [];
var resultsWithCRS = [];
var otherResults = [];
searchTerm = searchTerm.toLowerCase();
$.each(results, function(index, item) {
if (searchTerm.length <= 3 && item.text.toLowerCase().indexOf('(' + searchTerm + ')') != -1) {
resultsWithCRS.push(item);
} else if (utils.startsWith(item.text.toLowerCase(), searchTerm)) {
resultsStartingWith.push(item);
} else {
otherResults.push(item);
}
});
return resultsWithCRS.concat(resultsStartingWith.concat(otherResults));
}
return results;
};
var subscribeToValueChange = function($element, observable) {
var _base;
if (observable && typeof(_base = observable).subscribe === "function") {
_base.subscribe(function(val) {
return $element.select2('val', val);
});
}
}
function initialiseSelect2($element, settings) {
$element.select2(settings);
if (settings.selectedId && settings.selectedId() && settings.dataSource) {
$element.select2('val', settings.selectedId());
}
}
function init(element, valueAccessor, allBindingsAccessor) {
var settings = valueAccessor(),
allBindings = allBindingsAccessor(),
$element = $(element);
var defaultConfig = {
minimumInputLength: 2,
matchPreference: 'start',
selectOnClose: true
};
if (jqueryBrowser.platform == 'ipad' || jqueryBrowser.platform == 'iphone') {
defaultConfig.searchCssClass = 'ios-search';
}
settings = $.extend(defaultConfig, settings);
if (ko.isObservable(settings.selectedId) || ko.isObservable(settings.selectedText)) {
$element.on("select2:select", function(e) {
var selectedData = e.params.data;
if (settings.selectedId) {
settings.selectedId(selectedData.id);
}
if (settings.selectedText) {
settings.selectedText(selectedData.text);
}
});
}
if (settings.matchPreference == 'start') {
settings.matcher = matcher;
settings.sorter = sorter;
}
if (settings.dataSource) {
settings.data = ko.utils.unwrapObservable(settings.dataSource);
if (settings.data.length === 0) {
settings.placeholder = settings.originalPlaceholder;
} else {
settings.placeholder = settings.originalPlaceholder;
}
settings.dataSource.subscribe(function(newVal) {
settings.data = newVal;
if (settings.data.length === 0) {
settings.placeholder = settings.originalPlaceholder;
} else {
settings.placeholder = settings.originalPlaceholder;
}
initialiseSelect2($element, settings);
});
}
if (settings.placeholder && settings.dataSource) {
$element.prepend("<option></option>");
}
initialiseSelect2($element, settings);
if (allBindings.value) {
subscribeToValueChange($element, allBindings.value);
}
if (settings.selectedId) {
subscribeToValueChange($element, settings.selectedId);
}
// force keyboard to open on ios
if (jqueryBrowser.platform == 'ipad' || jqueryBrowser.platform == 'iphone') {
$(".select2-container, select").click(function() {
$('.select2-search__field').trigger('click').trigger('focus');
});
}
$element.on("select2:open", function(e) {
// force keyboard open on ios
if (jqueryBrowser.platform == 'ipad' || jqueryBrowser.platform == 'iphone') {
$('.select2-search__field').trigger('click').trigger('focus');
}
if (jqueryBrowser.desktop || $('body').innerWidth() > 767) {
var select2 = $(this);
var qttHome = $(e.target[0]).closest('.qtt-tabbed');
var qttHomeAnimate = $(e.target[0]).closest('.qtt-tabbed .qtt__search-bottom');
if (qttHome.hasClass('complete')) {
return;
}
if (qttHome.length) {
qttHomeAnimate.one('webkitTransitionEnd mozTransitionEnd oTransitionEnd otransitionend transitionend', function()
{
if (qttHome.hasClass('active')) {
if (jqueryBrowser.platform == 'ipad' || jqueryBrowser.platform == 'iphone') {
$(window).scrollTop($(window).scrollTop()+1);
$('span.select2-results').attr('style', 'display: block!important');
$('.select2-container--open .select2-dropdown').attr('style', 'left:0');
}
else{
select2.select2('open');
}
qttHome.addClass('complete');
}
});
if (!qttHome.hasClass('active') ) {
if (jqueryBrowser.platform == 'ipad' || jqueryBrowser.platform == 'iphone') {
$(window).scrollTop($(window).scrollTop()+1);
$('span.select2-results').attr('style', 'display: none!important');
$('.select2-container--open .select2-dropdown').attr('style', 'left:-9999px');
}
else{
select2.select2("close");
}
}
qttHome.addClass('active');
}
}
});
return ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
return $element.select2('destroy');
});
}
function update(element) {
$(element).trigger('change');
}
ko.bindingHandlers.select2 = {
init: init,
update: update
};
}
);