When using Chosen.js on a multiple select field, if there are over 500 options that the user has selected, the list just becomes ridiculously long.
Is there any way I could limit the number of show elements? For example when chosing over 3 options, the user will have (4) options are selected..., instead of them being listed.
I wonder why there's no such option in their documentation.
Thanks in advance.
You can use something like this:
$('.element').chosen().change(function() {
var totalSelected = $(this).find('option:selected').size();
var placeholder = $(this).find('option:first-child').text();
if(totalSelected > 3) {
$(this).next().find('.chosen-choices').find('li.search-choice').hide(),
$(this).next().find('.chosen-choices').find('.literal-multiple').show();
$(this).next().find('.chosen-choices').find('span.literal-multiple').text(placeholder + " ("+totalSelected+")");
}
});
The class literal-multiple is a custom element to show the totalSelected elements. You need to add it in the prototype of the chosen plugin:
file chosen.jquery.js
Chosen.prototype.set_up_html = function() {
//stuff
if(this.is_multiple) {
var selVal = this.default_text;
this.container.html('<ul class="chosen-choices"><span class="literal-multiple"></span></ul>');
}
};
SOrry I am unable to comment since I don't have enough reputation.
But to add to the previous answer, instead of adding a separate container,
why don't we just append the n users selected as a <li> item.
Something like this -
$('.element').chosen().change(function() {
var totalSelected = $(this).find('option:selected').size();
var placeholder = $(this).find('option:first-child').text();
if(totalSelected > 3) {
$(this).next().find('.chosen-choices').find('li.search-choice').hide(),
$(this).next().find('.chosen-choices')append('<li class="search-choice" <span>'+totalSelected+' users selected. </li>');
}
});
This seems to work for me.
Related
I have a webpage I'm building where I need to be able to select 1-9 members via a dropdown, which then provides that many input fields to enter their name. Each name field has a "suggestion" div below it where an ajax-fed member list is populated. Each item in that list has an "onclick='setMember(a, b, c)'" field associated with it. Once the input field loses focus we then validate (using ajax) that the input username returns exactly 1 database entry and set the field to that entry's text and an associated hidden memberId field to that one entry's id.
The problem is: when I click on the member name in the suggestion box the lose focus triggers and it attempts to validate a name which has multiple matches, thereby clearing it out. I do want it to clear on invalid, but I don't want it to clear before the onclick of the suggestion box name.
Example:
In the example above Paul Smith would populate fine if there was only one name in the suggestion list when it lost focus, but if I tried clicking on Raphael's name in the suggestion area (that is: clicking the grey div) it would wipe out the input field first.
Here is the javascript, trimmed for brevity:
function memberList() {
var count = document.getElementById('numMembers').value;
var current = document.getElementById('listMembers').childNodes.length;
if(count >= current) {
for(var i=current; i<=count; i++) {
var memberForm = document.createElement('div');
memberForm.setAttribute('id', 'member'+i);
var memberInput = document.createElement('input');
memberInput.setAttribute('name', 'memberName'+i);
memberInput.setAttribute('id', 'memberName'+i);
memberInput.setAttribute('type', 'text');
memberInput.setAttribute('class', 'ajax-member-load');
memberInput.setAttribute('value', '');
memberForm.appendChild(memberInput);
// two other fields (the ones next to the member name) removed for brevity
document.getElementById('listMembers').appendChild(memberForm);
}
}
else if(count < current) {
for(var i=(current-1); i>count; i--) {
document.getElementById('listMembers').removeChild(document.getElementById('listMembers').lastChild);
}
}
jQuery('.ajax-member-load').each(function() {
var num = this.id.replace( /^\D+/g, '');
// Update suggestion list on key release
jQuery(this).keyup(function(event) {
update(num);
});
// Check for only one suggestion and either populate it or clear it
jQuery(this).focusout(function(event) {
var number = this.id.replace( /^\D+/g, '');
memberCheck(number);
jQuery('#member'+number+'suggestions').html("");
});
});
}
// Looks up suggestions according to the partially input member name
function update(memberNumber) {
// AJAX code here, removed for brevity
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
document.getElementById('member'+memberNumber+'suggestions').innerHTML = self.xmlHttpReq.responseText;
}
}
}
// Looks up the member by name, via ajax
// if exactly 1 match, it fills in the name and id
// otherwise the name comes back blank and the id is 0
function memberCheck(number) {
// AJAX code here, removed for brevity
if (self.xmlHttpReq.readyState == 4) {
var jsonResponse = JSON.parse(self.xmlHttpReq.responseText);
jQuery("#member"+number+"id").val(jsonResponse.id);
jQuery('#memberName'+number).val(jsonResponse.name);
}
}
}
function setMember(memberId, name, listNumber) {
jQuery("#memberName"+listNumber).val(name);
jQuery("#member"+listNumber+"id").val(memberId);
jQuery("#member"+listNumber+"suggestions").html("");
}
// Generate members form
memberList();
The suggestion divs (which are now being deleted before their onclicks and trigger) simply look like this:
<div onclick='setMember(123, "Raphael Jordan", 2)'>Raphael Jordan</div>
<div onclick='setMember(450, "Chris Raptson", 2)'>Chris Raptson</div>
Does anyone have any clue how I can solve this priority problem? I'm sure I can't be the first one with this issue, but I can't figure out what to search for to find similar questions.
Thank you!
If you use mousedown instead of click on the suggestions binding, it will occur before the blur of the input. JSFiddle.
<input type="text" />
Click
$('input').on('blur', function(e) {
console.log(e);
});
$('a').on('mousedown', function(e) {
console.log(e);
});
Or more specifically to your case:
<div onmousedown='setMember(123, "Raphael Jordan", 2)'>Raphael Jordan</div>
using onmousedown instead of onclick will call focusout event but in onmousedown event handler you can use event.preventDefault() to avoid loosing focus. This will be useful for password fields where you dont want to loose focus on input field on click of Eye icon to show/hide password
I'm using the chosen plugin to build multiple select input fields. See an example here: http://harvesthq.github.io/chosen/#multiple-select
The default behavior disables an option if it has already been selected. In the example above, if you were to select "Afghanistan", it would be greyed out in the drop-down menu, thus disallowing you from selecting it a second time.
I need to be able to select the same option more than once. Is there any setting in the plugin or manual override I can add that will allow for this?
I created a version of chosen that allows you to select the same item multiple times, and even sends those multiple entries to the server as POST variables. Here's how you can do it (fairly easily, I think):
(Tip: Use a search function in chosen.jquery.js to find these lines)
Change:
this.is_multiple = this.form_field.multiple;
To:
this.is_multiple = this.form_field.multiple;
this.allows_duplicates = this.options.allow_duplicates;
Change:
classes.push("result-selected");
To:
if (this.allows_duplicates) {
classes.push("active-result");
} else {
classes.push("result-selected");
}
Change:
this.form_field.options[item.options_index].selected = true;
To:
if (this.allows_duplicates && this.form_field.options[item.options_index].selected == true) {
$('<input>').attr({type:'hidden',name:this.form_field.name,value:this.form_field.options[item.options_index].value}).appendTo($(this.form_field).parent());
} else {
this.form_field.options[item.options_index].selected = true;
}
Then, when calling chosen(), make sure to include the allows_duplicates option:
$("mySelect").chosen({allow_duplicates: true})
For a workaround, use the below code on each selection (in select event) or while popup opened:
$(".chosen-results .result-selected").addClass("active-result").removeClass("result-selected");
The above code removes the result-selected class and added the active-result class on the li items. So each selected item is considered as the active result, now you can select that item again.
#adam's Answer is working very well but doesn't cover the situation that someone wants to delete some options.
So to have this functionality, alongside with Adam's tweaks you need to add this code too at:
Chosen.prototype.result_deselect = function (pos) {
var result_data;
result_data = this.results_data[pos];
// If config duplicates is enabled
if (this.allows_duplicates) {
//find fields name
var $nameField = $(this.form_field).attr('name');
// search for hidden input with same name and value of the one we are trying to delete
var $duplicateVals = $('input[type="hidden"][name="' + $nameField + '"][value="' + this.form_field.options[result_data.options_index].value + '"]');
//if we find one. we delete it and stop the rest of the function
if ($duplicateVals.length > 0) {
$duplicateVals[0].remove();
return true;
}
}
....
Previously I asked how to do this and was directed to this:
<script>
jQuery.fn.filterByText = function(textbox) {
return this.each(function() {
var select = this;
var options = [];
$(select).find('option').each(function() {
options.push({value: $(this).val(), text: $(this).text()});
});
$(select).data('options', options);
$(textbox).bind('change keyup', function() {
var options = $(select).empty().scrollTop(0).data('options');
var search = $.trim($(this).val());
var regex = new RegExp(search,"gi");
$.each(options, function(i) {
var option = options[i];
if(option.text.match(regex) !== null) {
$(select).append(
$('<option>').text(option.text).val(option.value)
);
}
});
});
});
};
</script>
(http://www.lessanvaezi.com/filter-select-list-options/)
When I use this filter on the select box it filters both the unselected AND the selected. I'd like it to ONLY filter the unselected because if a user wants to ammend the selections and filters again, the previously selected items go away - unless they meet the filter criteria.
I'm not that good at JavaScript or JQuery and can't understand how I might tell the above script to ignore options that are ":selected" but filter all else.
Here's a jfiddle if it helps: http://jsfiddle.net/UmKXy/ I'd like option one and two to remain selected and in the list when user begins to type.
Thanks for help!
The solution you had would not work with selected elements because he created an array of options at the start and then matched those options against the regex(Without regards to what is actually selected). I've used spans to hide options in the past and created an example for you to see how it works. Here is the link : http://jsfiddle.net/rD6wv/
Here is the code
$(function() {
$("#filterByText").bind('keyup',function(){
var search = $.trim($(this).val());
var regex = new RegExp(search,"gi");
$("#filez").find('option').each(function(){
if(!$(this).is(':selected')){
if($(this).val().match(regex) === null) {
$(this).wrap('<span>');
}else if($(this).parent().is('span')){
$(this).parent().replaceWith($(this));
}
}
});
});
});
You simply need to loop through all the options of the select when you type in the textbox.
You then check if it is selected, if it is you do nothing, else you check if it matches the search filter, if it does you wrap it in a span, making it invisible, else it means you need to see it, so you check if it is already wrapped in a span, and in that case you replace it with the option so you can see it again.
to selected the non selected options, use this:
$('option:not[selected]') or $('#myselect > option:not[selected]')
to remove them, use this:
$('option:not[selected]').remove();
in css, :not filters for opposite of what comes in the curved brackets.
and [] is attribute selector.
so :not[selected] means: does not have an attribute whose key is "selected"
I have a client that wants to give users the option to select up to 5 additional options from a list. I like the Chosen.js concept, but how can I limit the selection? I suppose one solution is to use the onChange to count the number selected and then disable the remainder, but is there a neater solution?
Chosen provides a max_selected_options to allow you to do this:
$(".chzn-select").chosen({ max_selected_options: 5 });
max_selected_options: 5 is not working in my case. So I fixed as follows.
var countSelect = 0;
$(".chosen-select").chosen().change( function (e, params) {
if(params.deselected != undefined) { countSelect--; }
if(params.selected != undefined) { countSelect++; }
if(countSelect > 3) {
$('.chosen-select option[value="'+params.selected+'"]').attr('selected', false);
$(this).trigger('chosen:updated');
countSelect--;
}
});
Try it. Its working very smooth.
I`m trying to add options to my select menu in my custom plugin. I want to get these options from array that I have and with forearch or for to create these options.How can I do that?
Could you show us your code that generates the select box? If I'm guessing right, you might be able to do something like
var things = [];
var your = ["Derpy","Fluttershy","Applejack"];
for(var i = 0; i < your.length; i++) {
// The two values used to separate actual and display values if needed
things[i] = [your[i],your[i]];
}
// snip snip
tab.add({
type: 'select',
label: 'myAwesomePonySelector',
id: 'myAwesomePonySelector',
items : things
// your other definitions, like onShow and commit
});
I hope this helps.