Set select option by index - javascript

I have a dynamically generated dropdown select feature that numerically pages through a book. I wish to create a table of content feature that allows users to click a link to jump to pages within the book. I've implemented a vanilla javascript solution (see below) that selects by index BUT the update isn't triggered (page number changes in the pager but it doesn't advance the page).
I welcome a way to make the javascript change trigger or a jquery solution. Thanks!
function selectOption(index) {
document.getElementById("tei_pager").options.selectedIndex = index;
}
<select id="tei_pager" class="form-select">
<option value="10917">1</option>
<option value="10918">2</option>
<option value="10919">3</option>
</select>
Second Page
and this section of a separate jquery is binding the select
// Bind page changes to the select.
$("#tei_pager").change(function () {
Drupal.settings.islandora_paged_tei_seadragon_update_page(
$(this).val(),
$(this).children("option:selected").text()
);
});

I adapted a solution from here: Change <select>'s option and trigger events with JavaScript
Having the selection made by js rather than a mouseclick was inhibiting the process.
My solution looks like:
js
function selectOption(index){
if (index == 0) {
document.getElementById("tei_pager").options.selectedIndex = index;
}
else {
document.getElementById("tei_pager").options.selectedIndex = (index - 1);
}
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
document.getElementById("tei_pager").dispatchEvent(evt);
}
else {
document.getElementById("tei_pager").fireEvent("onchange");
}
}
html
<select id="tei_pager" class="form-select">
<option value="10917" selected="selected">1</option>
<option value="10918">2</option>
<option value="10919">3</option>
<option value="10920">4</option>
<option value="10921">5</option>
<option value="11192">6</option>
<option value="11193">7</option>
</select>
First Page
Sixth Page

You can set the value of the select tag.
function selectOption(val) {
document.getElementById("tei_pager").value = val;
}
<select id="tei_pager" class="form-select">
<option value="10917">1</option>
<option value="10918">2</option>
<option value="10919">3</option>
</select>
Second Page

If the change event of the select element is to trigger the Drupal code you have at the end of your question,
then change:
$("#islandora_paged_tei_seadragon_pager").change(function () { ....
to:
$("#tei_pager").change(function () { ....
UPDATE
If by ....dynamically generated dropdown select.... you mean to say that the select element is created after DOM ready event, then consider re-writing it as follows:
$(document).on('change', '#tei_pager', function () { ....

Related

Wrong display of Select Option Tag in Google Chrome [duplicate]

I've realized that Chrome, it seems, will not allow me to hide <option> in a <select>. Firefox will.
I need to hide the <option>s that match a search criteria. In the Chrome web tools I can see that they are correctly being set to display: none; by my JavaScript, but once then <select> menu is clicked they are shown.
How can I make these <option>s that match my search criteria NOT show when the menu is clicked?
For HTML5, you can use the 'hidden' attribute.
<option hidden>Hidden option</option>
It is not supported by IE < 11. But if you need only to hide a few elements, maybe it would be better to just set the hidden attribute in combination with disabled in comparison to adding/removing elements or doing not semantically correct constructions.
<select>
<option>Option1</option>
<option>Option2</option>
<option hidden>Hidden Option</option>
</select>
Reference.
You have to implement two methods for hiding. display: none works for FF, but not Chrome or IE. So the second method is wrapping the <option> in a <span> with display: none. FF won't do it (technically invalid HTML, per the spec) but Chrome and IE will and it will hide the option.
EDIT: Oh yeah, I already implemented this in jQuery:
jQuery.fn.toggleOption = function( show ) {
jQuery( this ).toggle( show );
if( show ) {
if( jQuery( this ).parent( 'span.toggleOption' ).length )
jQuery( this ).unwrap( );
} else {
if( jQuery( this ).parent( 'span.toggleOption' ).length == 0 )
jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
}
};
EDIT 2: Here's how you would use this function:
jQuery(selector).toggleOption(true); // show option
jQuery(selector).toggleOption(false); // hide option
EDIT 3: Added extra check suggested by #user1521986
I would suggest that you do not use the solutions that use a <span> wrapper because it isn't valid HTML, which could cause problems down the road. I think the preferred solution is to actually remove any options that you wish to hide, and restore them as needed. Using jQuery, you'll only need these 3 functions:
The first function will save the original contents of the select. Just to be safe, you may want to call this function when you load the page.
function setOriginalSelect ($select) {
if ($select.data("originalHTML") == undefined) {
$select.data("originalHTML", $select.html());
} // If it's already there, don't re-set it
}
This next function calls the above function to ensure that the original contents have been saved, and then simply removes the options from the DOM.
function removeOptions ($select, $options) {
setOriginalSelect($select);
$options.remove();
}
The last function can be used whenever you want to "reset" back to all the original options.
function restoreOptions ($select) {
var ogHTML = $select.data("originalHTML");
if (ogHTML != undefined) {
$select.html(ogHTML);
}
}
Note that all these functions expect that you're passing in jQuery elements. For example:
// in your search function...
var $s = $('select.someClass');
var $optionsThatDontMatchYourSearch= $s.find('options.someOtherClass');
restoreOptions($s); // Make sure you're working with a full deck
removeOptions($s, $optionsThatDontMatchYourSearch); // remove options not needed
Here is a working example: http://jsfiddle.net/9CYjy/23/
Ryan P's answer should be changed to:
jQuery.fn.toggleOption = function (show) {
$(this).toggle(show);
if (show) {
if ($(this).parent('span.toggleOption').length)
$(this).unwrap();
} else {
**if ($(this).parent('span.toggleOption').length==0)**
$(this).wrap('<span class="toggleOption" style="display: none;" />');
}
};
Otherwise it gets wrapped in too many tags
Select inputs are tricky in this way. What about disabling it instead, this will work cross-browser:
$('select').children(':nth-child(even)').prop('disabled', true);
This will disable every-other <option> element, but you can select which ever one you want.
Here is a demo: http://jsfiddle.net/jYWrH/
Note: If you want to remove the disabled property of an element you can use .removeProp('disabled').
Update
You could save the <option> elements you want to hide in hidden select element:
$('#visible').on('change', function () {
$(this).children().eq(this.selectedIndex).appendTo('#hidden');
});
You can then add the <option> elements back to the original select element:
$('#hidden').children().appendTo('#visible');
In these two examples it's expected that the visible select element has the id of visible and the hidden select element has the id of hidden.
Here is a demo: http://jsfiddle.net/jYWrH/1/
Note that .on() is new in jQuery 1.7 and in the usage for this answer is the same as .bind(): http://api.jquery.com/on
The toggleOption function is not perfect and introduced nasty bugs in my application. jQuery will get confused with .val() and .arraySerialize()
Try to select options 4 and 5 to see what I mean:
<select id="t">
<option value="v1">options 1</option>
<option value="v2">options 2</option>
<option value="v3" id="o3">options 3</option>
<option value="v4">options 4</option>
<option value="v5">options 5</option>
</select>
<script>
jQuery.fn.toggleOption = function( show ) {
jQuery( this ).toggle( show );
if( show ) {
if( jQuery( this ).parent( 'span.toggleOption' ).length )
jQuery( this ).unwrap( );
} else {
jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
}
};
$("#o3").toggleOption(false);
$("#t").change(function(e) {
if($(this).val() != this.value) {
console.log("Error values not equal", this.value, $(this).val());
}
});
</script>
Simple answer: You can't. Form elements have very limited styling capabilities.
The best alternative would be to set disabled=true on the option (and maybe a gray colour, since only IE does that automatically), and this will make the option unclickable.
Alternatively, if you can, completely remove the option element.
// Simplest way
var originalContent = $('select').html();
$('select').change(function() {
$('select').html(originalContent); //Restore Original Content
$('select option[myfilter=1]').remove(); // Filter my options
});
Since you're already using JS, you could create a hidden SELECT element on the page, and for each item you are trying to hide in that list, move it to the hidden list. This way, they can be easily restored.
I don't know a way offhand of doing it in pure CSS... I would have thought that the display:none trick would have worked.
You should remove them from the <select> using JavaScript. That is the only guaranteed way to make them go away.
!!! WARNING !!!
Replace the second "IF" by "WHILE" or doesn't work !
jQuery.fn.toggleOption = function( show ) {
jQuery( this ).toggle( show );
if( show ) {
while( jQuery( this ).parent( 'span.toggleOption' ).length )
jQuery( this ).unwrap( );
} else {
jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
}
};
this one seems to work for me in chrome
$("#selectid span option").unwrap();
$("#selectid option:not([filterattr=filtervalue])").wrap('<span/>');
Simply use option[value=your-value]{display:none;}
This works fine in Chrome, at least in 2022, as well as in safari and FF.
Modern solution is simply apply CSS hidden like:
<option value="" style="display:none;">Select Item</option>
Or with a class
<option value="" class="hidden">Please select</option>
Note in class case, add css like
.hidden {
display: none;
}
Late to the game, but most of these seem quite complicated.
Here's how I did it:
var originalSelect = $('#select-2').html();
// filter select-2 on select-1 change
$('#select-1').change(function (e) {
var selected = $(this).val();
// reset select ready for filtering
$('#select-2').html(originalCourseSelect);
if (selected) {
// filter
$('#select-2 option').not('.t' + selected).remove();
}
});
markup of select-1:
<select id='select-1'>
<option value=''>Please select</option>
<option value='1'>One</option>
<option value='2'>Two</option>
</select>
markup of select-2:
<select id='select-2'>
<option class='t1'>One</option>
<option class='t2'>Two</option>
<option>Always visible</option>
</select>
Simply, this can achieved by HTML too.
<select>
<option value="" disabled selected hidden>Please Choose</option>
<option value="0">hii</option>
<option value="1">hello</option>
</select>
2022 Answer Summary And Cross-Browser Solution
Currently, these methods do not work on Safari:
visibility: hidden
display: block
hidden attribute
So none of proposed solutions here using these methods works on Safari, so they can not be accepted.
Solution
The solution is to keep special options in an array, and hide/restore them on-demand. For example to show/hide day selection based on year/month selection:
When you initialize your component:
const tailDayOptions = [];
const saveTailDayOptions = () => {
const daySelector = document.querySelector('#daySelector');
for (let day = 29; day <= 31; day++) {
tailDayOptions[day - 1] = daySelector.querySelector(`option[value='${day - 1}']`);
}
}
When a user changes year or month:
for (let day = 29; day <= 31; day++) {
if (day <= daysInMonth) {
daySelector.appendChild(tailDayOptions[day - 1])
} else {
const dayOption = daySelector.querySelector(`option[value='${day - 1}']`);
if (dayOption) {
daySelector.removeChild(dayOption);
}
}
}
How does it work
It saves options for day 29,30 and 31 to a tailDayOptions array
When user changes the year or month, daysInMonth are calculated
If a given day (e.g. 29th) is not present in a given year-month and it is available in the select options, it gets removed from there
If a given day is available in a given year-month it gets re-added to the select from the tailDayOptions array
Compatibility
Compatible with Firefox, Chrome and Safari. Should be compatible with all other browsers.

How to use jQuery select / .change() to reveal a hidden div

I have the following select field and based on whether the class .show-x-trend or show-x is selected I would like to conditionally reveal a separate div. If .show-x-trend <option> is selected, I'd like to reveal the already hidden #x-axis-trend-wrap <div> and if show-x option is selected I'd like to reveal the already hidden #x-axis-wrap <div>. In the code below, you'll see that I have both CSS classes and also values assigned to the 3 selection options because I tried to achieve the effect a few different ways but so far with no luck.
<div id="visualize-wrap">
<h3>Visualization Shows</h3>
<select id="visualize-shows" name="visualize">
<option class="no-show" value="00">Select One</option>
<option class="show-x-trend" value="01">Trend Over Time</option>
<option class="show-x" value="02">Breakdown of Sum Total</option>
<option class="show-x" value="03">Side-by-side Comparison</option>
</select>
</div>
You can use hasClass method to determine if the selected option contains the required class or not and act accordingly.
$('#visualize-shows').change(function(){
var $selectedOption = $(this).find('option:selected');
$('#x-axis-trend-wrap')
.toggle( $selectedOption.hasClass('show-x-trend'));
$('#x-axis-wrap')
.toggle( $selectedOption.hasClass('show-x'));
});
Working demo - http://jsfiddle.net/X2dPt/
Try something like this
$("#visualize-shows").change(function() {
$selected = $(this).find('option:selected'); // get selected option
if ($selected.hasClass('show-x-trend')) { // check the class
$('#x-axis-trend-wrap').toggle(); // toggle display
} else if ($selected.hasClass('show-x')) {
$('#x-axis-wrap').toggle();
}
});
this uses .hasClass()

Changing selection in a select with the Chosen plugin

I'm trying to change the currently selected option in a select with the Chosen plugin.
The documentation covers updating the list, and triggering an event when an option is selected, but nothing (that I can see) on externally changing the currently selected value.
I have made a jsFiddle to demonstrate the code and my attempted ways of changing the selection:
$('button').click(function() {
$('select').val(2);
$('select').chosen().val(2);
$('select').chosen().select(2);
});
From the "Updating Chosen Dynamically" section in the docs: You need to trigger the 'chosen:updated' event on the field
$(document).ready(function() {
$('select').chosen();
$('button').click(function() {
$('select').val(2);
$('select').trigger("chosen:updated");
});
});
NOTE: versions prior to 1.0 used the following:
$('select').trigger("liszt:updated");
My answer is late, but i want to add some information that is missed in all above answers.
1) If you want to select single value in chosen select.
$('#select-id').val("22").trigger('chosen:updated');
2) If you are using multiple chosen select, then may you need to set multiple values at single time.
$('#documents').val(["22", "25", "27"]).trigger('chosen:updated');
Information gathered from following links:
1) Chosen Docs
2) Chosen Github Discussion
Sometimes you have to remove the current options in order to manipulate the selected options.
Here is an example how to set options:
<select id="mySelectId" class="chosen-select" multiple="multiple">
<option value=""></option>
<option value="Argentina">Argentina</option>
<option value="Germany">Germany</option>
<option value="Greece">Greece</option>
<option value="Japan">Japan</option>
<option value="Thailand">Thailand</option>
</select>
<script>
activateChosen($('body'));
selectChosenOptions($('#mySelectId'), ['Argentina', 'Germany']);
function activateChosen($container, param) {
param = param || {};
$container.find('.chosen-select:visible').chosen(param);
$container.find('.chosen-select').trigger("chosen:updated");
}
function selectChosenOptions($select, values) {
$select.val(null); //delete current options
$select.val(values); //add new options
$select.trigger('chosen:updated');
}
</script>
JSFiddle (including howto append options):
https://jsfiddle.net/59x3m6op/1/
In case of multiple type of select and/or if you want to remove already selected items one by one, directly within a dropdown list items, you can use something like:
jQuery("body").on("click", ".result-selected", function() {
var locID = jQuery(this).attr('class').split('__').pop();
// I have a class name: class="result-selected locvalue__209"
var arrayCurrent = jQuery('#searchlocation').val();
var index = arrayCurrent.indexOf(locID);
if (index > -1) {
arrayCurrent.splice(index, 1);
}
jQuery('#searchlocation').val(arrayCurrent).trigger('chosen:updated');
});

Form change with JavaScript

I have two drop down lists:
<select name="branch">
<option value="b">Blacksburg</option>
<option value="c">Christiansburg</option>
<option value="f">Floyd</option>
<option value="m">Meadowbrook</option>
</select>
but I would like the second list to be different based upon what is selected from the first list. So FREX Blacksburg's might be:
<select name="room">
<option value="Kitchen">Kitchen Side</option>
<option value="Closet">Closet Side</option>
<option value="Full">Full Room</option>
</select
While Christiansburg's is:
<select name="room">
<option value="Window">Window Side</option>
<option value="Door">Door Side</option>
<option value="Full">Full Room</option>
and of course the options are also different for the other branches...
Is it possible to change the second drop down list based on what they select for the first one? I have used JavaScript a teensy bit, but not much so please explain in detail.
Yes, this is called a drilldown.
What you want to do is attach an onChange handler to your first dropdown that will grab new values based on the selected value (of the first dropdown) and populate those values into the second dropdown.
I recommend doing this with jQuery. It will make the experience much more pleasant. That being said:
var optionsMap = {
b: {
Kitchen: "Kitchen Side",
Closet: "Closet Side",
Full: "Full Room"
},
c: {
Window: "Window Side",
Door: "Door Side",
Full: "Full Room"
},
...
};
jQuery("#firstSelect").change(function() {
/* "this" is a reference to firstSelect element. Wrapping jQuery(...)
around it turns it into a jQuery object. Then you get the value
of the selected element with .val() */
var $select = jQuery(this);
var value = $select.val();
/* I'm doing the following to illustrate a point; in some cases
you may have to get it from a database with an AJAX request.
Basically YMMV */
var newOptions = optionsMap[value];
/* remove all the old options */
jQuery("#secondSelect").find("option").remove();
/* Iterate over the hash that you got and create new option
objects that use the key of the hash as the option value
and the value of the hash as the option text */
jQuery.each(newOptions, function(option, value) {
jQuery("#secondSelect").append(
jQuery("<option></option>").attr("value", option)
.text(value)
);
});
});
First, these kind of DOM modifying actions are made much easier with jQuery. It abstracts a lot of browser-specific crap away from you, making it much easier to do your thing. However, since you didn't mention the jQuery, I'll address the JavaScript issues. This is completely possible with JavaScript.
Second, you're going to want to give all of your select elements ids. This will make it much easier for JavaScript to identify them. Ids must be unique. I'm just going to follow the convention of naming the id after the name of the element.
Third, what we do is listen for the JavaScript event onchange on the select element and then do something with it (note the id attributes).
<select id="branch" name="branch" onchange="handleChange();">
<option value="b">Blacksburg</option>
<option value="c">Christiansburg</option>
<option value="f">Floyd</option>
<option value="m">Meadowbrook</option>
</select>
<select id="room" name="room">
</select>
The above code assigns the event listener handleChange to the branch select element. When a change event is fired, handleChange will be called. Now let's define the handleChange function:
<script type="text/javascript">
var handleChange = function() {
// get a handle to the branch select element
var branch = document.getElementById('branch');
// get the index of the selected item
var index = branch.selectedIndex;
// handle displaying the correct second select element
if (index === 0) {
// if the index is 0 (the first option,) call the Blacksburg function
doBlacksburg();
// I'll leave this up to you ;)
} else if (index === 1) {
// more stuff
}
}
</script>
Now we'll define the function that updates the second select list with Blacksburg information:
var doBlacksburg = function() {
var blacksburg = document.getElementById('room');
blacksburg.options[0] = new Option("Kitchen Side", "Kitchen", true, false);
blacksburg.options[1] = new Option("Closet Side", "Closet", false, false);
blacksburg.options[2] = new Option("Full Room", "Full", false, false);
}
That will update the second select list with the Blacksburg options. Reference for the JavaScript Option object.
That code is by no means extensive, but it should be enough to get you started. Like I said earlier, all of the above code can be done in as few as 5 lines of jQuery and it might be worth your time to look into jQuery or a similar library.
Are you familiar with / comfortable using a library like jQuery? I'd approach it with something like this:
var roomOpts = {
b: [
'<option value="Kitchen">Kitchen Side</option>',
'<option value="Closet">Closet Side</option>',
'<option value="Full">Full Room</option>'
]
....
};
$('select[name=branch]').change(function () {
$('select[name=room']).html(roomOpts[$(this).val()].join(''));
});
You can use an onchange event handler on the first list that calls a function to change the other list(s).
Look at this one:
http://www.webdeveloper.com/forum/showthread.php?t=97765

How can you programmatically tell an HTML SELECT to drop down (for example, due to mouseover)?

How can you programmatically tell an HTML select to drop down (for example, due to mouseover)?
This used to actually be possible with HTML+Javascript, despite everywhere else people say it is not, but it was deprecated later on and does not work now.
However, this only worked in Chrome. Read more if you're interested.
According to W3C Working Draft for HTML5, Section 3.2.5.1.7. Interactive Content:
Certain elements in HTML have an activation behavior, which means that the user can activate them. This triggers a sequence of events dependent on the activation mechanism [...] for instance using keyboard or voice input, or through mouse clicks.
When the user triggers an element with a defined activation behavior in a manner other than clicking it, the default action of the interaction event must be to run synthetic click activation steps on the element.
<select> being an Interactive Content, I believed that it is possible to programatically display its <option>s. After a few hours of playing around, I discovered that using document.createEvent() and .dispatchEvent() works.
That said, demo time. Here is a working Fiddle.
// <select> element displays its options on mousedown, not click.
showDropdown = function(element) {
var event;
event = document.createEvent('MouseEvents');
event.initMouseEvent('mousedown', true, true, window);
element.dispatchEvent(event);
};
// This isn't magic.
window.runThis = function() {
var dropdown = document.getElementById('dropdown');
showDropdown(dropdown);
};
<select id="dropdown">
<option value="Red">Red</option>
<option value="Green">Green</option>
<option value="Blue">Blue</option>
</select>
<br>
<button id="fire" type="button" onclick="runThis()">Show dropdown items</button>​
If anyone finds a way to do the same but not in Chrome, please feel free to modify this fiddle.
​
Xavier Ho's answer is covering how to solve the issue in most browsers currently out there. But, it's good practice 'not to dispatch/modify' events by JavaScript anymore. (Like, mousedown in this case)
From version 53+, Google Chrome will not perform default action for un-trusted events. Such as events created or modified by script, or dispatched via dispatchEvent method. This change is for aligning with Firefox and IE which I think already not performing the action.
For testing purposes, Fiddle provided Xavier's answer won't work in chrome 53+. (I don't test it FF and IE).
Links for reference:
https://www.chromestatus.com/features/5718803933560832
https://www.chromestatus.com/features/6461137440735232
And initMouseEvent is also deprecated
This is the closest I could get, change the size of the element onmouseover, and restore the size onmouseout:
<select onMouseOut="this.size=1;" onMouseOver="this.size=this.length;">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
I have this same problem and the easier way I found to solve this was with HTML and CSS.
First, make you <select> transparent (opacity: 0;). Then, place your button over the <select>. The click over the button will be caught by the <select> component.
select{
opacity: 0;
position: absolute;
}
select:hover~button {
background: orange;
}
div * {
width: 100px;
}
<div>
<select>
<option>option 1</option>
<option>option 2</option>
<option>option 3</option>
</select>
<button>click</button>
</div>
You can't do this with a HTML select tag, but you can do it with JavaScript and HTML. There are variety of existing controls that do this - for instance, the "suggest" list attached to the SO "interesting/ignored tag" entry, or Gmail's lookup for email adresses.
There are many JavaScript+HTML controls that provide this capability--look for autocomplete controls for ideas.
See this link for the Autocomplete control...http://ajaxcontroltoolkit.codeplex.com/
I think this is no longer possible in Chrome.
It seems version 53 of chrome disables this functionality as stated by Asim K T.
According to the spec
http://www.w3.org/TR/DOM-Level-3-Events/#trusted-events
Trusted Events should not fire the default action (except click
event).
They have however enabled it in webview, but I have not tested this.
We have found that some webviews are using fastclick inside them and
due to a risk of breakage we are going to allow mousedown on selects
even if they are untrusted.
And in this discussion the idea to let developers open a dropdown programatically is abandoned.
If any one is still looking for this :
<select id="dropdown">
<option value="Red">Red</option>
<option value="Green">Green</option>
<option value="Blue">Blue</option>
</select>
<br>
<button id="fire" type="button" >Show dropdown items</button>
Javascript:
var is_visible=false;
$(document).ready(function(){
$('#fire').click(function (e) {
var element = document.getElementById('dropdown');
if(is_visible){is_visible=false; return;}
is_visible = true;
var event;
event = document.createEvent('MouseEvents');
event.initMouseEvent('mousedown', true, true, window);
element.dispatchEvent(event);
/* can be added for i.e. compatiblity.
optionsSelect.focus();
var WshShell = new ActiveXObject("WScript.Shell");
WshShell.SendKeys("%{DOWN}");
*/
e.stopPropagation();
return false;
});
$(document).click(function(){is_visible=false; });
});
Update:
One till there is no perfect solution to this problem, But you can try to avoid this scenario. Why do you want to do this. i was wondering for a solution few months back to make a select plugin for mobile devices
https://github.com/HemantNegi/jquery.sumoselect
Finally ended up with masking the custom div (or any other element) with a transparent select element, so that it can directly interacts with user.
Here's the best way I found. NOTE It only works with IE on Windows and your web would probably need to be in a secure zone - because we access the shell. The trick is that ALT-Down Arrow is a shortcut key to open a select drop down.
<button id="optionsButton" style="position:absolute;top:10px;left:10px;height:22px;width:100px;z-index:10" onclick="doClick()">OPTIONS</button>
<select id="optionsSelect" style="position:absolute;top:10px;left:10px;height:20px;width:100px;z-index:9">
<option>ABC</option>
<option>DEF</option>
<option>GHI</option>
<option>JKL</option>
</select>
<script type="text/javascript">
function doClick() {
optionsSelect.focus();
var WshShell = new ActiveXObject("WScript.Shell");
WshShell.SendKeys("%{DOWN}");
}
</script>
Stop thinking that one thing is impossible, nothing is impossible to do, when you want to do.
Use this expand JS function created by a guy.
http://code.google.com/p/expandselect/
Include this JS and just call that passing the param as your select id, like that:
ExpandSelect(MySelect)
If anyone is still looking for this,
This is how I solved it.
This is a solution based on the fact that the selection looks like it is expanded when the size in increased. We can increase size to make it look expanded. And reduce to make it seem closed. This way we can handle most use-cases by just having focus and blur listeners.
Select element needs to be absolutely positioned because increasing size will increase vertical height of element. If you have elements below, they will be pushed down if this is not done.
I have a wrapper code, that wraps the element and provides open and close methods.
Check this fiddle for usage: https://jsfiddle.net/10ar2ebd/16/
var SelectionWrapper = function(element, maxSize, selectCb) {
var preventDefault = function(e) {
e.preventDefault();
e.stopPropagation();
}
var isOpen = false;
var open = function() {
if (!isOpen) {
element.size = maxSize;
// Remove prevent default so that user will be able to select the option
// Check why we prevent it in the first place below
element.removeEventListener('mousedown', preventDefault);
// We focus so that we can close on blur.
element.focus();
isOpen = true;
}
};
var close = function() {
if (isOpen) {
element.size = 1;
// Prevent default so that the default select box open behaviour is muted.
element.addEventListener('mousedown', preventDefault);
isOpen = false;
}
};
// For the reason above
element.addEventListener('mousedown', preventDefault);
// So that clicking elsewhere closes the box
element.addEventListener('blur', close);
// Toggle when click
element.addEventListener('click', function(e) {
if (isOpen) {
close();
// Call ballback if present
if(selectCb) {
selectCb(element.value);
}
} else {
open();
}
});
return {
open: open,
close: close
};
};
// Usage
var selectionWrapper = SelectionWrapper(document.getElementById("select_element"), 7, function(value) {
var para = document.createElement("DIV");
para.textContent = "Selected option: " + value;
document.getElementById("result").appendChild(para);
});
document.getElementById("trigger").addEventListener('click', function() {
selectionWrapper.open();
});
Here is the solution on https://jsfiddle.net/NickU/ahLy83mk/50/
It uses size="x" to open the dropdown while maintaining the dropdown and parent positions. The code also uses CSS styles to hide the right scroll area when it is not needed. I modified the code I found on stackoverflow, fixed the problems and added styling.
HTML:
<div>DIV example: <select id="dropdownDiv">
<option value="Alpha">Alpha</option>
<option value="Beta">Beta</option>
<option value="Gamma">Gamma</option>
</select>
</div>
<table id='tab1'>
<tr><td>Empty Cell</td></tr>
<tr><td> <select id="dropdown1">
<option value="Red">Red</option>
<option value="Green">Green</option>
<option value="Blue">Blue</option>
</select>
</td>
<tr><td><select id="dropdown2">
<option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="15">1</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option></select>
</td></tr>
<tr><td>Empty Cell</td></tr></table>
<br><button id="fire" type="button" onclick="openDropdown('dropdownDiv', this)" >Show dropdownDiv items</button>
<button id="fire" type="button" onclick="openDropdown('dropdown1', this)" >Show dropdown1 items</button>
<button id="fire" type="button" onclick="openDropdown('dropdown2', this)" >Show dropdown2 items</button>
JavaScript:
var lastClosedElem = null;
var maxItemsInDropDown = 12;
function openDropdown(elementId, opener)
{
if (lastClosedElem !== null && lastClosedElem === opener)
{
lastClosedElem = null;
return;
}
lastClosedElem = opener;
function down()
{
var $this = $(this);
var td = $this.closest('td,div');
if (td && td.length > 0)
td.height(td.height());
var pos = $this.offset();
var len = $this.find("option").length;
if (len > 1 && len < maxItemsInDropDown)
{
$this.addClass('no-scroll');
$this.addClass('noArrow');
}
else if (len > maxItemsInDropDown)
{
len = maxItemsInDropDown;
}
$this.css("position", "absolute");
var _zIndex = $this.css("zIndex");
if (!_zIndex)
_zIndex = 'auto';
$this.attr("_zIndex", _zIndex);
$this.css("zIndex", 9999);
$this.attr("size", len); // open dropdown
$this.unbind("focus", down);
$this.focus();
}
var up = function()
{
var $this = $(this);
$this.css("position", "static");
$this.attr("size", "1");
$this.removeClass('no-scroll');
$this.removeClass('noArrow');
var _zIndex = $this.attr("zIndex");
if (_zIndex)
{
$this.css("zIndex", _zIndex);
}
$this.unbind("blur", up);
$this.unbind("click", upClick);
$this.focus();
}
function upClick(e)
{
up.call(this);
lastClosedElem = null;
}
$("#" + elementId).focus(down).blur(up).click(upClick).trigger('focus');
}
CSS:
.no-scroll { cursor: pointer;}
.no-scroll::-webkit-scrollbar {display:none;}
.no-scroll::-moz-scrollbar {display:none;}
.no-scroll::-o-scrollbar {display:none;}
.no-scroll::-google-ms-scrollbar {display:none;}
.no-scroll::-khtml-scrollbar {display:none;}
.noArrow {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
padding-left: 3px;
padding-right: 3px;
}
/* Cosmetic styles */
#tab1 tbody tr:nth-child(even) > td, div
{ background: linear-gradient( 180deg, #efefef 1%, #eeeeee 15%, #e2e2e2 85%);
}
#tab1 tbody tr td
{ padding: 4px;
}
#tab1
{ border: 1px solid silver;
}
I may be wrong, but I don't believe that is possible with the default select box. You could do something with JS & CSS that achieves the desired result, but not (to my knowledge) the vanilla SELECT.
This is not exactly what you asked for, but I like this solution for its simplicity. In most cases where I am wanting to initiate a dropdown, it is because I'm validating that the user has actually made a selection. I change the size of the dropdown and focus it, which nicely highlights what they've skipped:
$('#cboSomething')[0].size = 3;
$('#cboSomething')[0].focus();
Opening an "HTML select" is possible through some workarounds mentioned in this question and similar ones. However a cleaner way of doing this is to add a select library to your project like "select2" or "chosen".
For instance, opening a select2 programmatically would be as easy as:
$('#target-select').select2('open');
I don't know if I'm fully understanding the question, but to open a dropdown, this simple approach worked for me.
You have an element:
<span onclick="openDropdown();">Open dropdown</span>
You have a dropdown:
<select class="dropdown">
<option value="A">Value A</option>
<option value="B">Value B</option>
<option value="C">Value C</option>
</select>
And with JavaScript you can do the following:
document.querySelector('.dropdown').focus();
let elSelected = null;
function bindSelectClick(el){
if(el.target !== elSelected){
$(elSelected).trigger('blur');
$(document).unbind('click', bindSelectClick)
}
}
$('select.shared_date').on('focus', function (){
// do something
elSelected = this;
$(document).on('click', bindSelectClick)
}).on('blur', function (){
// do something
}).on('change', function (){
// do something
})
Select does not lose focus after its menu is closed.
With a separate function, we check whether the click was on the select or elsewhere. If the elements are not equal, then you can fire some kind of event

Categories

Resources