JQuery Select Box and Loop Help - javascript

Thanks for reading. I'm a bit new to jQuery, and am trying to make a script I can include in all my websites to solve a problem that always drives me crazy...
The problem:
Select boxes with long options get cut off in Internet Explorer. For example, these select boxes:
http://discoverfire.com/test/select.php
In Firefox they are fine, but in IE, the options are cut off to the width of the select when they drop down.
The solution:
What I am looking to do, is create a script that I can include in any page that will do the following:
Loop through all the selects on the page.
For each select:
A. Loop through its options.
B. Find the width of the longest option.
C. Bind a function to expand the select to that width on focus (or maybe click...).
D. Bind a function to shrink to it's original width on blur.
I've managed to do most of step #2 for one select box.
I found that getting the options width was a problem (especially in IE), so I looped through and copied the text of each option to a span, measured the span width, and used the longest one as the width the select will be expanded to. Perhaps somebody has a better idea.
Here is the code
<script type='text/javascript'>
$(function() {
/*
This function will:
1. Create a data store for the select called ResizeToWidth.
2. Populate it with the width of the longest option, as approximated by span width.
The data store can then be used
*/
// Make a temporary span to hold the text of the options.
$('body').append("<span id='CurrentOptWidth'></span>");
$("#TheSelect option").each(function(i){
// If this is the first time through, zero out ResizeToWidth (or it will end up NaN).
if ( isNaN( $(this).parent().data('ResizeToWidth') ) ) {
$(this).parent().data( 'OriginalWidth', $(this).parent().width() );
$(this).parent().data('ResizeToWidth', 0);
$('CurrentOptWidth').css('font-family', $(this).css('font-family') );
$('CurrentOptWidth').css('font-size', $(this).css('font-size') );
$('CurrentOptWidth').css('font-weight', $(this).css('font-weight') );
}
// Put the text of the current option into the span.
$('#CurrentOptWidth').text( $(this).text() );
// Set ResizeToWidth to the longer of a) the current opt width, or b) itself.
//So it will hold the width of the longest option when we are done
ResizeToWidth = Math.max( $('#CurrentOptWidth').width() , $(this).parent().data('ResizeToWidth') );
// Update parent ResizeToWidth data.
$(this).parent().data('ResizeToWidth', ResizeToWidth)
});
// Remove the temporary span.
$('#CurrentOptWidth').remove();
$('#TheSelect').focus(function(){
$(this).width( $(this).data('ResizeToWidth') );
});
$('#TheSelect').blur(function(){
$(this).width( $(this).data('OriginalWidth') );
});
alert( $('#TheSelect').data('OriginalWidth') );
alert( $('#TheSelect').data('ResizeToWidth') );
});
</script>
and the select:
<select id='TheSelect' style='width:50px;'>
<option value='1'>One</option>
<option value='2'>Two</option>
<option value='3'>Three</option>
<option value='42,693,748,756'>Forty-two billion, six-hundred and ninety-three million, seven-hundred-forty-some-odd..... </option>
<option value='5'>Five</option>
<option value='6'>Six</option>
<option value='7'>Seven...</option>
</select>
Hopefully this will run for you if you want to run it, or you can see it in action here: http://discoverfire.com/test/select.php.
What I need help with:
This needs a bit of polish, but seems to work ok if you specify the select box.
However, I don't seem to be able to figure out how to apply it to all select boxes on the page with a loop. So far, I have this:
$('select').each(
function(i, select){
// Get the options for the select here... can I use select.each...?
}
);
Also, is there a better way to get the length of the longest option for each select? The span is close, but not very exact. The problem is that IE returns zero for the option widths of the actual selects.
Any ideas are very welcome, both for the questions asked, and any other improvements to my code.
Thanks!!

To modify each select, try this:
$('select').each(function(){
$('option', this).each(function() {
// your normalizing script here
})
});
The second parameter (this) on the second jQuery call scopes the selecter ('option'), so it is essentially 'all option elements within this select'. You can think of that second parameter defaulting to 'document' if it's not supplied.

I was able to replicate your results for all selects on a page in IE7 using this code, which I find much simpler than the span method you are using, but you can replace the "resize" function with whatever code suits your needs.
function resize(selectId, size){
var objSelect = document.getElementById(selectId);
var maxlength = 0;
if(objSelect){
if(size){
objSelect.style.width = size;
} else {
for (var i=0; i< objSelect.options.length; i++){
if (objSelect[i].text.length > maxlength){
maxlength = objSelect[i].text.length;
}
}
objSelect.style.width = maxlength * 9;
}
}
}
$(document).ready(function(){
$("select").focus(function(){
resize($(this).attr("id"));
});
$("select").blur(function(){
resize($(this).attr("id"), 40);
});
});

Related

Asp.Net core multi select Listbox with a single click [duplicate]

I thought this would be a simple hack, but I've now been searching for hours and can't seen to find the right search term. I want to have an ordinary multiple select box (<select multiple="multiple">) except I don't want the user to have to hold down the control key to make multiple selections.
In other words, I want a left click to toggle the <option> element that's under the cursor without changing any of the others. In other other words, I want something that looks like a combo list box but behaves like a group of check boxes.
Can anybody suggest a simple way to do this in Javascript? Thanks.
Check this fiddle: http://jsfiddle.net/xQqbR/1022/
You basically need to override the mousedown event for each <option> and toggle the selected property there.
$('option').mousedown(function(e) {
e.preventDefault();
$(this).prop('selected', !$(this).prop('selected'));
return false;
});
For simplicity, I've given 'option' as the selector above. You can fine tune it to match <option>s under specific <select> element(s). For ex: $('#mymultiselect option')
Had to solve this problem myself and noticed the bugged behavior a simple interception of the mousedown and setting the attribute would have, so made a override of the select element and it works good.
jsFiddle: http://jsfiddle.net/51p7ocLw/
Note: This code does fix buggy behavior by replacing the select element in the DOM. This is a bit agressive and will break event handlers you might have attached to the element.
window.onmousedown = function (e) {
var el = e.target;
if (el.tagName.toLowerCase() == 'option' && el.parentNode.hasAttribute('multiple')) {
e.preventDefault();
// toggle selection
if (el.hasAttribute('selected')) el.removeAttribute('selected');
else el.setAttribute('selected', '');
// hack to correct buggy behavior
var select = el.parentNode.cloneNode(true);
el.parentNode.parentNode.replaceChild(select, el.parentNode);
}
}
<h4>From</h4>
<div>
<select name="sites-list" size="7" multiple>
<option value="site-1">SITE</option>
<option value="site-2" selected>SITE</option>
<option value="site-3">SITE</option>
<option value="site-4">SITE</option>
<option value="site-5">SITE</option>
<option value="site-6" selected>SITE</option>
<option value="site-7">SITE</option>
<option value="site-8">SITE</option>
<option value="site-9">SITE</option>
</select>
</div>
techfoobar's answer is buggy, it unselects all options if you drag the mouse.
Sergio's answer is interesting, but cloning and removing events-bound to a dropdown is not a nice thing.
Try this answer.
Note: Doesn't work on Firefox, but works perfectly on Safari/Chrome/Opera. (I didn't test it on IE)
EDIT (2020)
After 5 years since my original answer, I think best practice here is to replace the dropdown with checkboxes. Think about it, that's the main reason why checkboxes exist in the first place, and it works nicely with old browsers like IE & modern mobiles without any custom JS to handle all the wacky scenarios.
Necromancing.
The selected answer without jQuery.
Also, it missed setting the focus when an option is clicked, because you have to do this yourself, if you write e.preventDefault...
Forgetting to do focus would affect CSS-styling, e.g. bootstrap, etc.
var options = [].slice.call(document.querySelectorAll("option"));
options.forEach(function (element)
{
// console.log("element", element);
element.addEventListener("mousedown",
function (e)
{
e.preventDefault();
element.parentElement.focus();
this.selected = !this.selected;
return false;
}
, false
);
});
I had same problem today, generally the advice is to use a list of hidden checkboxes and emulate the behavior via css, in this way is more easy to manage but in my case i don't want to modify html.
At the moment i've tested this code only with google chrome, i don't know if works with other browser but it should:
var changed;
$('select[multiple="multiple"]').change(function(e) {
var select = $(this);
var list = select.data('prevstate');
var val = select.val();
if (list == null) {
list = val;
} else if (val.length == 1) {
val = val.pop();
var pos = list.indexOf(val);
if (pos == -1)
list.push(val);
else
list.splice(pos, 1);
} else {
list = val;
}
select.val(list);
select.data('prevstate', list);
changed = true;
}).find('option').click(function() {
if (!changed){
$(this).parent().change();
}
changed = false;
});
Of course suggestions are welcome but I have not found another way

When options disabled, select not works on IE 11 - jQuery [duplicate]

Currently I am using jQuery to hide/show select options using following code.
$("#custcol7 option[value=" + sizeValue + "]").hide();
This works fine in Firefox, but doesnt do any good in other browsers. How to I hide options from select in Chrome, Opera and IE?
I just came across this and instead of cloning the entire select over and over I just replaced the options that need to be hidden with span elements and hiding the spans ( though the browser didnt visually show them anyway, I think ) - you may need to change your code ( if complex ) to iterate through the spans for complex logic.
The spans store a reference to the option and replace themselves with it when they need to be shown.
This code can obviously be refactored and prettified.
http://fiddle.jshell.net/FAkEK/12/show/
EDIT #2 ( USE THIS INSTEAD ): It occurred to me that instead of doing all this clone/reference/replace crap, just wrap the option with a span, hide the span, and on show just replace the span with the option again..
http://fiddle.jshell.net/FAkEK/25/show/
I think meder has provided valid answer and here it is slightly changed to reflect what works for me:
$.fn.optVisible = function( show ) {
if( show ) {
this.filter( "span > option" ).unwrap();
} else {
this.filter( ":not(span > option)" ).wrap( "<span>" ).parent().hide();
}
return this;
}
Tested with (long live BrowserStack):
Windows XP: IE 6.0, Firefox 3.0, Safari 4.0, Opera 10.0, Chrome 14.0
Windows 8: IE 10.0 Metro
iOS 3.2 (iPad), iOS 6.0 (iPhone 5)
Android 1.6 (Sony Xperia X10)
jsfiddle
You don't, it's not supported in IE (and assumably not in Chrome or Opera either). You would have to remove the options altogether and add them back later if you want them to be truly invisible. But in most cases a simple disabled="disabled" should suffice and is a heck of a lot simpler than handling the removing and adding of options.
try detach().
you can reattach it later if needed using append() or insertAfter()
To Remove options use:
var opt=$("option").detach();
To show options use:
opt.appendTo( "select" );
Just deleted it and store it in a var in your JavaScript. You can just create the new object when you need it later.
Otherwise try the disabled attribute mentioned above.
/**
* Change visibility of select list option elements
* #param {boolean} stateVal show hidden options if true; hide it otherwise. If not setted then toggle visibility, based on it's current state
*/
$.fn.toggleOptionVisibility = function (stateVal) {
var isBool = typeof stateVal === "boolean";
return this.each(function () {
var $this = $(this);
if (isBool) {
if (stateVal) $this.filter("span > option").unwrap();
else $this.filter(":not(span > option)").wrap("<span>").parent().hide();
}
else {
$this.filter("span > option").toggleOptionVisibility(true);
$this.filter(":not(span > option)").toggleOptionVisibility(false);
}
});
};
the way you did it should work in chrome but nvm.Here is another way
select = $('#custcol7');
select.find('option[value=["'+sizeValue +'"]').remove();
and if you want to show it again:
select.append('<option value="'+sizeValue+'"></option>');
It works perfectly on every browser and its really simple code. The problem is if you want to hide several options it is more typing .. but that can be solved by putting them into variables if they don't change dynamically like that :
var options = '<option value="'+sizeValue1+'"></option><option value="'+sizeValue2+'"></option><option value="'+sizeValue3+'"></option>';
select.append(options);
This way if you have to remove/append on several places you only typed the options once.Hope i gave another interesting option. Best Regards.
There's also the the .load method:
s_parent.change(function(){
s_child.load('./fetch_options.php",{'v',s_parent.val()});
}
The 'fetch_options.php' script would simply print the option tags based on whatever data source you use and the parent value(s) being passed in.
using the solution provided by AuthorProxy, it works fine for IE but when I attempt to do a .val() on the dropdown in firefox I get some funky values that don't make any sense. I have modified their option to include browser specific functionality, hide/show works for firefox.
$.fn.toggleOptionVisibility = function (stateVal) {
var isBool = typeof stateVal === "boolean";
return this.each(function () {
var $this = $(this);
if (navigator.userAgent.indexOf('MSIE') > -1 || navigator.userAgent.indexOf('Trident') > -1) {
if (isBool) {
if (stateVal) $this.filter("span > option").unwrap();
else $this.filter(":not(span > option)").wrap("<span>").parent().hide();
}
else {
$this.filter("span > option").toggleOptionVisibility(true);
$this.filter(":not(span > option)").toggleOptionVisibility(false);
}
}
else {
if (isBool) {
$this.show();
}
else {
$this.hide();
}
}
});
};
My take is bit different to other answers.
The aim is not to hide the options but just make them disable(to keep the UI consistent).
My Scenario :
I have multiple selects in a form and when an user selects an option in one of the selects the other selects should disable this option and vice versa. User is restricted from selecting the same option which is already selected. We normally disable the option but for IE 7 which does not support it. User also gets an option to add new selects.
Solution :
On load :
If the browser is IE7 then while populating the the selects and disabling the already selected options on other selects I am adding a custom attribute to the option("data-ie7-disabled") and also changing the color of the disabled options to '#cccccc'(which is the standard color for disabled options). This makes the UI look same across browsers.
On Change :
I save the previous option in a local variable(this is saved on focus).
When a user tries to change an option
User selects a complete new option which is not selected in any other dropdown. Then I loop through other selects and change the color and add custom attribute to this selected option on other selects.
When user selects an option that is already selected(The option which has grayed out color). I check if the option has this custom attribute on it first. If it has then > I simply revert the option to the previous one with an error message saying "This option is already selected or BLAH BLAH".
When user changes his existing option to a brand new option which is not selected in any other dropdown's. I again loop through all the other select options and remove the color on it and also the custom attribute.
Hope this helps.
You can use through combinations of var $opt=$('select>option').clone() and $('select option[value="'+val+'"').remove().
There is another example: try this. https://jsfiddle.net/sherali/jkw8fxzf/12/
var $secondOption= $('#second-choice>option').clone();
$("#first-choice").change(function() {
var userSelected = $(this).val();
$('#second-choice').html($secondOption);
$('#second-choice option[value="'+userSelected+'"').remove()
});
You will need to remove it and then add it again for Internet Explorer.
To remove:
$("#custcol7 option[value=" + sizeValue + "]").remove();
To add:
$("#custcol7").append( "<option value='sizeValue'>sizeValue</option>" );
Note that you need to have sizeValue also in the option text, to actually see something.
You can also replace the html within the select.
Html:
<input id="Button1" type="button" value="hide option" />
<select id="foo">
<option >stuff</option>
<option >stuff2</option>
</select>
Jquery:
$("#Button1").change(function () {
$('#foo').html('<option >stuff</option>');
});
Not exactly what you want, but perhaps it helps. For smaller dropdowns, it is definitely easier.
In IE 11(Edge), the following code is working.
$("#id option[value='1']").remove();
and to ad back,
$('<option>').val('1').text('myText').appendTo('#id');
meder's solution is what I went with for this, but with a small tweak to prevent it from wrapping an option in a span that was already in a span:
$.fn.hideOption = function() {
this.each(function() {
if (!$(this).parent().is('span')) {
$(this).wrap('<span>').hide();
}
});
};
$.fn.showOption = function() {
this.each(function() {
var opt = $(this).find('option').show();
$(this).replaceWith(opt);
});
};
<html>
<head><script>
$(document).ready(function(){
$("#l1").change(function(){
var selectedId=$("#dl1 option[value='"+$(this).val()+"']").attr("id");
$("#dl2 option[data-id ='"+selectedId+"']").removeAttr('disabled');
$("#dl2 option[data-id !='"+selectedId+"']").attr('disabled','disabled');
$("#l2").val("");
});
});
</script></head>
<body>
<label for="l1">choose country</label>
<input list="dl1" name="l1" id="l1" type='select'>
<datalist id="dl1" name="dl1">
<option value="India" id=1>
<option value="US" id=2>
<option value="Germany" id=3>
</datalist>
<br>
<label for="l2">choose City</label>
<input list="dl2" name="l2" id="l2" type='select'>
<datalist id="dl2">
<option value="New Delhi" id="11" data-id="1">
<option value="Washington DC" id="12" data-id="2">
<option value="Berlin" id="13" data-id="3">
<option value="Mumbai"id="14" data-id="1">
<option value="NewYork" id="15" data-id="2">
<option value="Munich" id="16" data-id="3">
</datalist>
</body>
</html>
You can use this:
$("#custcol7 option[value=" + sizeValue + "]").css({display:'none'});
It works fine on all browsers except Safari and Opera. I'm searching for another best solution :)

how to sset the default setting

i know this is very dumb question but i m stuck in this problem i create a form in jsp and in form i use a dropdown list which provide the option for change the css on Labels of form like ..."Left Align, Right Align, None" starting two optionare working properly "None" option functionality is when i selected this option so the css which is applied by two option is removed and the default setting of this form is show............ please suggest me how i do it ...............here i m showing my code
JavaScript Code
function placement() {
var dropVal = $('#styleField').val();
if (dropVal == "la") {
$("._check").each(function(index) {
$('label').css("float", "left");
});
}
if (dropVal == "ra") {
$("._check").each(function(index) {
$('label').css("float", "right");
});
}
if (dropVal == "de") {
// $("._check").each(function(index) {
// $('._check').find('checkbox').css("float" , "left")
// $("float").remove();
});
}
}
this is my code and _check is a class which is applied on checkbox
Html Code
<select id="styleField" name="styleOfField" class="form-control select2me" data-placeholder="Placement Of labels" onclick="placement();">
<option> - </option>
<option value="la"> Left Aligned </option>
<option value="ra"> Right Aligned </option>
<option value="de"> Default </option>
</select>
so please help me ...Thanks in advance
To reset the float, you want to set float: none:
$('label').css('float','none');
But your code has other issues. You are iterating through each _check for no apparent reason. $('label') will target all labels, regardless of the presence of any ._check element.
Are you looking for label inside a ._check element? In that case, you can select them with the descendant selector, , and you don't need to iterate over the results, .css works across entire sets:
$('._check label').css('float','none');
You appear to have two options for the default behavior. One which has the value "de", and one which doesn't have a value at all. The latter will not match any condition in your placement function.
Furthermore, the code you've shown us has unmatched brackets, but I suppose that may just be a pasting issue.
You could also do this with classess. That way you don't have to manually set float: none, but you could simply omit setting a float when none is needed.
CSS
.la { float: left; }
.ra { float: right; }
JavaScript
function placement() {
$('._check label')
.removeClass('la ra')
.addClass($('#styleField').val());
}
Some notes on your commented out attempts:
$('._check').find('checkbox') would look for all <checkbox/> children of a class="check" element. If you want to search for an <input type="checkbox" /> you may use the :checkbox selector.
$('float').remove() would look for all <float/> elements in the document and remove them.
Update addressing your comment
Now that you've clarified that you want all labels with a _check class, my code above doesn't do that. It selects all labels that are the descendants of an element with a check class. Your code selects all labels regardless of whether they have a check class, and does so repeatedly because of your iteration.
If you truly want all labels in the document that has a class named _check, the code would be:
$('label._check').css('float','none');

change style of <texarea> using getElementsByTagName textAlign from center to left

I have a script to change the text alignment for the textarea with the id textbox1 below:
// <![CDATA[
function alignFix() {
document.getElementById("textbox1").style.textAlign="left";
}
// ]]>
Here's the markup:
<textarea cols="36" rows="25" readonly="readonly" id="textbox1" name="textbox" style="text-align: center;">dynamic text populates via another script unrelated to problem</textarea>
Here's the trigger:
<select class="c9" onchange="showCenterTemplates(this); alignFix();">
It works just fine. Now I have more than one textarea I need this script to work on, so I thought it would be a simple switch from document.getElementById to document.getElementsByTagName but to my ignorance/surprise, that didn't work so well.
I've searched the questions and forums and Google, and have found examples of document.getElementsByTagName in action, but not in the manners I need it to.
It seems like when using getElementsByTagName, one must always declare a variable (can anyone confirm if this is true?) so I tried:
// <![CDATA[
function alignFix() {
var textbox = document.getElementsByTagName('textarea');
style_textbox = textbox.style;
style_textbox.textAlign="left";
}
// ]]>
but with that I'm getting a style_textbox is null or not an object error when testing. Can anyone help me out please? Thanks very much in advance.
P.S. The reason for the script is because the original contents of the textareas need to be centered, but when the user begins to select templates from the <select> to populate dynamically in the <textarea> using the showCenterTemplates() script, those templates need to have left aligned text inside the <textarea>. Hope that makes sense.
getElementsByTagName returns an array of elements, so you have to loop over it:
var i,j, textbox = document.getElementsByTagName('textarea');
for (i=0, j=textbox.length; i<j; i++) {
textbox[i].style.textAlign='left';
}
EDIT: per request in the comment, a short explanation:
i is incremented from 0 (zero) as long it doesn't reach the size of the array
textbox is the array, textbox.lenght returns its size
for every i (as in i is 0, i is 1 etc.) textbox[i] represents a position in the array
since the array is filled with HTML Elements, every position in the array is an Element,
and has a style attribute

JQuery/Javascript Clear/Reset Drop down List to original values

Ok dokey, got a bit of jquery up and running, lovely stuff.
$(document).ready(function() {
$inputs = $("#tbxProdAC, #ddlBuyer, #txtbxHowMany, radTopx");
$.each($inputs, function() {
$(this).focus(function() {
$.each($inputs, function() {
$(this).val('');
$(this).attr('checked', false);
})
});
})
});
However, in my drop down list, I wish to retain the orignal value rather than clear it altogether.
Is there a way I can specify the individual values i.e. tbxProdAC ='', ddlBuyer = Original Value, txtbxHowMany='', radTopx =unchecked, etc?
have you tryed:
document.getElementById('formId').reset();
try it this way:
$(document).ready(function() {
$("#tbxProdAC, #ddlBuyer, #txtbxHowMany, radTopx").focus(function() {
document.getElementById('formId').reset();
});
});
You'll have to go through each one separately to do that.
i.e.
$('#tbxProcAC').val('');
$('#ddlBuyer').val($('#ddlBuyer')[0].defaultValue);
$('#txtbxHowMany').val('');
$('#radTopx').attr('checked',false);
Perhaps the second line there may be of most intrest to you - it shows how to access the original 'default' value.
Comment if you've any questions, good luck!
You can use the data function in JQuery - you can store all the existing values and call them again when you need them
in JQuery can select First Option <option value="0" > </option> first option value is zero and text is empty.
now
$('#DropDown').find('option:first').attr('selected', 'selected');
$('#DropDown')[0].selectedIndex = 0;
$('#DropDown') -> select dropdown
find('option:first') -> find first option
attr('selected', 'selected') -> set attribute selected.
Try this simple way
document.getElementById(‘drpFruits’).options.length=0;

Categories

Resources