I am trying to use more than 10000 datas in my combobox and I have this code
$.fn.select2.amd.define('select2/data/customAdapter',[
'select2/data/array',
'select2/utils'
],
function (ArrayAdapter, Utils) {
function CustomDataAdapter ($element, options) {
CustomDataAdapter.__super__.constructor.call(this, $element, options);
}
Utils.Extend(CustomDataAdapter, ArrayAdapter);
CustomDataAdapter.prototype.query = function (params,callback) {
console.log(params);
var pageSize,
results;
pageSize = 20;
results = _.filter(content, function (e) {
return (params.term === "" || e.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0);
});
console.log(results);
callback({
results: results.slice((params.page - 1) * pageSize, params.page * pageSize),
// retrieve more when user hits bottom
more : results.length >= params.page * pageSize
});
};
return CustomDataAdapter;
}
);
var customAdapter=$.fn.select2.amd.require('select2/data/customAdapter');
objCmb.select2({
allowClear: true,
disabled: dis,
placeholder: Empty,
data: content,
formatLoadMore : 'Loading more...',
dataAdapter:customAdapter
});
when I use the select2 this error appear
TypeError: params.term is undefined
...ms.term === "" || e.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0)
The problem is that when someone focuses the select2 control, there's no really a term, so the params object is empty (e.g. {}). You can see this in this JsFiddle (just try to search for something).
If you want to get rid of that error, you can modify your custom query function to account for that:
CustomDataAdapter.prototype.query = function (params, callback) {
var pageSize, results;
pageSize = 20;
results = _.filter(content, function (e) {
return (params.term == null || params.term === "" || e.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0);
// ^^^^^^^^^^^^^^^^^^^
});
callback({
results: results.slice((params.page - 1) * pageSize, params.page * pageSize),
more: results.length >= params.page * pageSize
});
};
This will be working as you'd expect it to (modified fiddle).
I would also like to note that your code example does not include the select population with items, so it's not present in the above fiddles either.
Related
I have a page where I am adding jquery-ui autocompletes dynamically
My .autocomplete() code includes a $.getJSON('my_url', my_payload) where, in my_payload,' I am trying to send the request.term (what I typed into the jqueryui textbox) as well as the id of the jquery ui text box.
The problem is, for all the dynamically added textboxes, they were just picking up the term and id of the original autocomplete.
I managed to find a way to get the id of the added (not original) autocomplete by wrapping the autocomplete in a function that has the added field passed in as a parameter, but because the 'term' is in the request, which comes from .autocomplete, I do not know how to get this for the new ones.
https://jsfiddle.net/amchugh89/1L8jvea5/4/
//=======dynamic formset script from https://medium.com/all-about-
django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0======
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
if ($(this).attr('name')){
var name = $(this).attr('name').replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
if($(this).attr('id').includes('gl')){
console.log($(this).attr('id'))
make_autocomplete($(this))
}
}
});
newElement.find('label').each(function() {
var forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('<span class="glyphicon glyphicon-minus" aria-hidden="true"></span>');
return false;
}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;
});
//====================
//AUTOCOMPLETE==(that allows for multiple ACs
https://stackoverflow.com/questions/24656589/using-jquery-ui-autocomplete-
with-multiple-input-fields)===================================
function make_autocomplete(ee) {
ee.on("focus", function(){ //.autocomplete({
$(this).autocomplete({
minLength: 2,
source: function( request, response ) {
var term = request.term;
//with the formset, I want to get the row for which I am typing in the
'term'
var this_formset_row_autocomplete_id
=ee.attr('id');//$(this.element).prop("id");//
$(this).attr('id');
console.log(this_formset_row_autocomplete_id);
var corresponding_branch_html_id =
this_formset_row_autocomplete_id.replace('gl_account','branch');
var this_formset_row_branch_sym_id =
$('#'+corresponding_branch_html_id).val();
//console.log(corresponding_branch_html_id, this_formset_row_branch_sym_id)
var appended_data={term:term,
this_formset_row_branch_sym_id:this_formset_row_branch_sym_id};
console.log(appended_data);
$.getJSON( "{% url 'dashapp:account_autocomplete' %}", appended_data,
function( data,
status, xhr ) {
//cache[ term ] = data;
response( data );
});
}
});
});
}//end function make_autocomplete
var ee =$( ".account_autocomplete" )
make_autocomplete(ee)
//===============
You may want to try to make it more simple for testing. Something like:
function make_autocomplete(obj) {
obj.autocomplete({
minLength: 2,
source: function(req, resp) {
var myData = {
term: req.term,
original_form_branch_id: $(this).closest("form").attr("id"),
this_formset_row_branch_sym_id: $(this).closest(".row").find("select").val()
}
$.getJSON("myurl", myData, function(results) {
resp(results);
});
}
});
}
Fiddle: https://jsfiddle.net/Twisty/pywb9nhv/23/
This uses .closest() to gather details from the relative objects. Also I do not see any benefit to initializing Autocomplete on focus event.
If you would like further help, please provide Example Data that can be used in a working example.
Hope that helps a little.
I am in process of upgrading select2 version 3.5.1 to 4.0. I required to use query method for mandate.
There are two specific problem arises
minimumInputLength is not taking effect
When user focus searchbox, The past results are displayed with Searching.. is first item. (If I assign empty result then it resolves the problem but then it displays No results found message)
Please refer to my code snippet below.
var self = this, $view = $(view);
$.fn.select2.amd.require(['select2/data/array', 'select2/utils', 'select2/data/minimumInputLength'], function (ArrayData, Utils, MinimumInputLength) {
function CustomData($element, options) {
CustomData.__super__.constructor.call(this, $element, options);
this.options = options;
}
Utils.Extend(CustomData, ArrayData);
CustomData.prototype.query = function (params, callback) {
//callback({ results: [] });
self.searchText(params.term);
q(ko.unwrap(self.qPromise)).then(function () {
var select2data = $.map(ko.unwrap(self.dataSource), function (obj) {
obj.id = obj.id || obj.Id + obj.KeyDoc;
obj.text = obj.text || obj.Headline;
return obj;
});
callback({ results: select2data });
});
}
// Decorate after the adapter is built
Utils.Decorate(CustomData, MinimumInputLength);
$view.select2({
dataAdapter: CustomData,
multiple: ko.unwrap(self.multiple),
templateResult: ko.unwrap(self.formatFunc),
escapeMarkup: function (markup) { return markup; },
dropdownParent: $('.' + ko.unwrap(self.containerClass)),
placeholder: ko.unwrap(self.placeHolderCaption),
minimumInputLength: 1,
allowClear: true
});
});
Every time I wish to assign new options in suggestion list (no cached no stored)
Please suggest workaround.
Thanks in advanced
Is it possible to setup select2 control to accept custom choice
in single selection mode (tags:false) ?
When typing your choice in the search box instead of seeing "No results found",
just see what you typing in and select it by click or pressing enter.
Well - I finally found solution myself.
I override original SelectAdapter adding new choice every time you type in
and delete previous temporary choices:
$.fn.select2.amd.require(['select2/data/select', 'select2/utils'],
function (SelectAdapter, Utils) {
function XSelectAdapter($element, options) {
XSelectAdapter.__super__.constructor.call(this, $element, options);
}
Utils.Extend(XSelectAdapter, SelectAdapter);
XSelectAdapter.prototype.query = function (params, callback) {
var data = [];
var self = this;
var $options = this.$element.children();
var have_exact_match = false;
$options.each(function () {
var $option = $(this);
if (!$option.is('option') && !$option.is('optgroup')) {
return;
}
var option = self.item($option);
if (option.xtemp === true) {
$(this).remove(); // previously typed-in choice - delete
return;
}
if (option.term === params.term) {
have_exact_match = true; // will not choice if have exact match
}
var matches = self.matches(params, option);
if (matches !== null) {
data.push(matches);
}
});
if (!have_exact_match) {
self.addOptions(this.option({selected: false, id: params.term, text: params.term, xtemp: true}));
data.push({selected: false, id: params.term, text: params.term});
}
callback({
results: data
});
};
$('#your_select2').select2({dataAdapter:XSelectAdapter});
});
Select2 Jquery Plugin
I was having hard time how to override the default message for minimum length input in jquery Select2.
by default the plugin gives the following message.
Default Text
Please enter 1 more characters
My requirement was to show, the following text
Required Text
Enter 1 Character
please share the solution.
Thanks.
The accepted answer does not work for Select2 v4. Expanding on the comment by #IsaacKleinman, the way to override the default messages for an individual Select2 instance is through the language property:
var opts = {
language: {
inputTooShort: function(args) {
// args.minimum is the minimum required length
// args.input is the user-typed text
return "Type more stuff";
},
inputTooLong: function(args) {
// args.maximum is the maximum allowed length
// args.input is the user-typed text
return "You typed too much";
},
errorLoading: function() {
return "Error loading results";
},
loadingMore: function() {
return "Loading more results";
},
noResults: function() {
return "No results found";
},
searching: function() {
return "Searching...";
},
maximumSelected: function(args) {
// args.maximum is the maximum number of items the user may select
return "Error loading results";
}
}
};
$('#mySelect').select2(opts);
To override the functions globally, call the set function on the defaults (according to the docs):
$.fn.select2.defaults.set("key", "value")
However, in our code we do it like this:
$.fn.select2.defaults.defaults['language'].searching = function(){
return 'Custom searching message'
};
I don't know why we don't follow the docs, but it works.
Solution
Here is the solution that i have found out.
Prior to v4
Initialize
$("input[name='cont_responsible'],input[name='corr_responsible'],input[name='prev_responsible'],input[name='pfmea_responsible']").select2({
minimumInputLength: 1,
formatInputTooShort: function () {
return "Enter 1 Character";
},
});
Note
Do not forget to add this code in your document. ready function.
$(document).ready(function () {
});
I shared my solution, any better solutions are welcome.
Thanks.
Using v4 and onwards
The following worked for V4. #Isaac Kleinman
language: { inputTooShort: function () { return ''; } },
You can try this on version 4.0 or higher
you can see reference for answer frome this link :
issues reference
$("#select2").select2({
minimumInputLength: 1,
language: {
inputTooShort: function() {
return 'Please Add More Text';
}
}
});
If you are using django-select2, just add attributes to your form in forms.py:
widget=BookSelect2Widget(
attrs={'data-minimum-input-length': 1}
)
Override the function behaviour like below
$.fn.select2.defaults = $.extend($.fn.select2.defaults, {
formatMatches: function(matches) {
return matches + $filter('translate')('label.matches.found');
},
formatNoMatches: function() {
return $filter('translate')('noMatches.found');
},
formatInputTooShort: function(input, min) {
var n = min - input.length;
return $filter('translate')('label.please.enter ') + n + $filter('translate')(' more.characters') + (n == 1 ? "" : "s");
},
formatInputTooLong: function(input, max) {
var n = input.length - max;
return $filter('translate')('please.delete ') + n + $filter('translate')('')('delete.characters') + (n == 1 ? "" : "s");
},
formatSelectionTooBig: function(limit) {
return $filter('translate')('select.only') + limit + $filter('translate')('select.item ') + (limit == 1 ? "" : "s");
},
formatLoadMore: function(pageNumber) {
return $filter('translate')('load.results');
},
formatSearching: function() {
return $filter('translate')('label.search');
}
});
}
I am building an advanced search UI similar to the TFS query builder web interface. Using knockout for the client side implementation and have everything more or less working except the final validation to make certain required items are basically selected. It sort-of works as far as giving me a validation error if I select an item and then de-select the item. Which is fine, but I would like to have the form validate when hitting the search button.
I am pretty sure I need to make use of the ko.validatedobservable method, I'm just not sure exactly how. Anyway, I have a fiddle to look at: http://jsfiddle.net/sstolp/uXBSA/ if anyone has the time or inclination to help me out. I would deeply appreciate it.
Thank you for your time.
scvm.SearchLine = function () {
var self = this;
self.selectedField = ko.observable().extend({ required: true });
self.selectedOperator = ko.observable().extend({ required: true });
self.firstdate = ko.observable(new Date());
self.lastdate = ko.observable(new Date());
self.thedate = ko.observable(new Date());
return self;};
scvm.Criteria = function () {
var self = this,
lines = ko.observableArray([]),
// Put one line in by default
loadInitialData = function () {
lines.push(new scvm.SearchLine());
},
rowcount = ko.computed(function () {
return lines().length;
}),
// Operations
addLine = function () {
lines.push(new scvm.SearchLine());
},
removeLine = function (line) {
lines.remove(line);
},
search = function () {
var data = $.map(lines(), function (line) {
return line.selectedField() ? {
selectedField: line.selectedField().searchfield,
selectedOperator: line.selectedOperator().name,
} : undefined
});
alert("Send to server: " + JSON.stringify(data));
},
clear = function () {
lines.removeAll();
};
return {
lines: lines,
loadInitialData: loadInitialData,
rowcount: rowcount,
addLine: addLine,
removeLine: removeLine,
search: search,
clear: clear
};
}();
Yes, all your SearchLine objects must be wrapped into ko.validatedObservable. Also you should implement computed property which will check isValid() for each criteria line and return global validity flag.
scvm.SearchLine = function () {
var self = this;
self.selectedField = ko.observable().extend({ required: true });
self.selectedOperator = ko.observable().extend({ required: true });
self.firstdate = ko.observable(new Date());
self.lastdate = ko.observable(new Date());
self.thedate = ko.observable(new Date());
return ko.validatedObservable(self);
};
scvm.Criteria = function () {
// ...
return {
lines: lines,
loadInitialData: loadInitialData,
rowcount: rowcount,
addLine: addLine,
removeLine: removeLine,
search: search,
clear: clear,
// new property that indicates validity of all lines
linesValid: ko.computed(function(){
var items = lines();
for (var i = 0, l = items.length; i < l; i++)
if (!items[i].isValid()) return false;
return true;
})
};
}();
This new property can be used in enable binding of you "Search" button:
<input type="button"
data-bind="enable: linesValid, click: search"
title="Clicking this button will run a search."
value="Search" />
I've modified your fiddle. Take a look: http://jsfiddle.net/ostgals/uXBSA/8/
Update:
Also we should slightly modify Criteria.search method, since our line array contains observables rather than objects:
//...
search = function () {
var data = $.map(lines(), function (line) {
line = ko.utils.unwrapObservable(line);
return line.selectedField() ? {
selectedField: line.selectedField().searchfield,
selectedOperator: line.selectedOperator().name,
} : undefined
});
alert("Send to server: " + JSON.stringify(data));
},
//...