I have created a javascript search in select element.
option tag does not get any CSS to hide or display none, for this solution I have removed unmatched option and make a backup for removed option for reset list button.
It's working fine but I have a problem, I have about 19000 option for this select list.
search works fine but when I hit reset button, only 9500 option from 19000 comes back.
I appreciate your help.
Here is the code:
CodePen Demo
HTML
<h1>Search in select "option" tag</h1>
<select multiple name="selectMenu" id="selectMenu" style="width:100px" size=10>
<option value ="item 1">item 1</option>
<option value ="item 2">item 2</option>
<option value ="thing 3">thing 3</option>
<option value ="item 4">item 4</option>
<option value ="stuff 5">stuff 5</option>
<option value ="stuff 6">stuff 6</option>
<option value ="stuff 7">stuff 7</option>
<option value ="item 8">item 8</option>
</select>
<p>Search within this list</p>
<input type=text name="search" id="search" onkeypress="searchItems();">
<br>
<input type=button value="Search" onclick="searchItems();">
<input type=button value="Reset List" onclick="resetList();">
Javascript
var itemList = null;
var itemListOriginal = new Array();
var backup = false;
function searchItems() {
itemList = document.getElementById("selectMenu");
var searchStrObj = document.getElementById("search");
var itemDescription = "";
// replace white space with wild card
var searchString = searchStrObj.value;
searchString = searchString.replace(" ", ".*");
var re = new RegExp("(" + searchString + ")", "i"); //"i" sets "ignore case" flag
if (itemListOriginal.length < 1)
backup = true;
else
backup = false;
// loop through options and check for matches
for (i=itemList.options.length - 1; i >=0 ; i--) {
itemDescription = itemList.options.item(i).text;
if (backup) {
hash = new Array();
hash['name'] = itemDescription;
hash['value'] = itemList.options.item(i).value;
itemListOriginal[i] = hash;
}
if (!itemDescription.match(re)) {
itemList.remove(i);
}
}
return false;
}
function resetList() {
//hack! remove all elements from list before repopulating
for (i=itemList.options.length - 1; i >=0 ; i--) {
itemList.remove(i);
}
for (i=0; i < itemListOriginal.length; i++) {
hash = itemListOriginal[i];
//option = new Option(hash['name'], hash['value']); REMOVED
//itemList.options.add(option, i); REMOVED
itemList.options[i] = new Option(hash['name'], hash['value'], false, false);
}
document.getElementById("search").value = "";
}
DEMO
I've observed that in your code backup is changed every time you call the function searchitems().
Thus erasing the old values that were stored in it.
So I've changed that
It is working fine but I have a problem,
I have about 19000 option for this select list.
search works fine but when I hit reset button,
only 9500 option from 19000 comes back.
That is the reason behind that. So I've modified your code and added a global variable backupList in that.
so when the unwanted elements are removed old elements aren't deleted in my code but instead, new removed elements are appended to old removed elements using += shorthand operator.
also rather creating options dynamically and using .add or .append or any similar javascript method I'm using .innerHTML for simplicity as you can see in the code. only problem is that now after you click reset elements will not be sorted as it was in the first case, You'll need to sort them believe me it is easy. for sorting refer: sort select menu alphabetically?.
var itemList = null;
var itemListOriginal = new Array();
var backup = false;
var backupList =""; // To store removed elements
function searchItems() {
itemList = document.getElementById("selectMenu");
var searchStrObj = document.getElementById("search");
var itemDescription = "";
var searchString = searchStrObj.value;
searchString = searchString.replace(" ", ".*");
var re = new RegExp("(" + searchString + ")", "i"); //"i" sets "ignore case" flag
for (i=itemList.options.length - 1; i >=0 ; i--) {
itemDescription = itemList.options.item(i).text;
var hash = new Array();
hash['name'] = itemDescription;
hash['value'] = itemList.options.item(i).value;
itemListOriginal[i] = hash;
if (!itemDescription.match(re)) {
itemList.remove(i); //Remove Unwanted Elements
backupList+="<option value='"+ hash['value']+"'>"+itemDescription+"</option>";
/* append new unwanted elements with previous,
initially it is blank "".
This is Important
*/
}
}
return false;
}
function resetList() {
var itemList = document.getElementById("selectMenu");
itemList.innerHTML+=backupList; /* Add removed elements to list.
alternate to .append,.add or similar function*/
backupList=""; // Make Backup Empty!
document.getElementById("search").value = "";
}
Hope it helps! cheers :)!
Related
I'd like to add the same options elements to more than one select, using one JavaScript function.
<select id="select1" name="select1"></select>
<select id="select2" name="select2"></select>
I want selects become:
<select id="select1" name="select1">
<option value="0">Txt1</option>
<option value="1">Txt2</option>
<option value="2">Txt3</option>
</select>
<select id="select2" name="select2">
<option value="0">Txt1</option>
<option value="1">Txt2</option>
<option value="2">Txt3</option>
</select>
Here is part of function to fill selects with options:
function window_onload(){
var SpecTxt = new Array("Txt1","Txt2","Txt3");
for(var i=0; i<SpecTxt.length; i++) {
var oOption = document.createElement("OPTION");
oOption.text = SpecTxt[i];
oOption.value=i;
select1.add(oOption); // Option to first SELECT
select2.add(oOption); // Option to second SELECT
}
}
But I've got Internet Explorer Script Error "Invalid argument", result is only one first option in "select1" and no options in "select2". If I remove from function window_onload() the last string select2.add(oOption);, there are no IE errors and "select1" is filled as must be, but "select2" is empty. How is it possible in JS to add the same options to different SELECTs?
Update
The reason why the Demo didn't work for IE is because it doesn't recognize the property .valueAsNumber.
From:
var opts = qty.valueAsNumber;
To:
var opts = parseInt(qty.value, 10);
When you create an option within the loop:
var oOption = document.createElement("OPTION");
That is only one <option> not two <option>s. So that is the reason why:
select1.add(oOption); // Succeeds
select2.add(oOption); // Fails
You can either make 2 <option>s per loop:
var oOption1 = document.createElement("OPTION");
var oOption2 = document.createElement("OPTION");
OR try cloneNode(). See Demo below:
Demo
// See HTMLFormControlsCollection
var form = document.forms.ui;
var ui = form.elements;
var qty = ui.qty0;
var s0 = ui.sel0;
var s1 = ui.sel1;
// Declare a counter variable outside of loop
var cnt = 0;
// Add event handler to the change event of the input
qty.onchange = addOpt;
/* Get the value of user input as a number
|| within the for loop...
|| create an <option> tag...
|| add text to it with an incremented offset...
|| add a incremented value to it...
|| then clone it...
|| add original <option> to the first <select>...
|| add duplicate <option> to the second <select>
*/
function addOpt(e) {
var opts = parseInt(qty.value, 10);
for (let i = 0; i < opts; i++) {
var opt = document.createElement('option');
opt.text = 'Txt' + (cnt + 1);
opt.value = cnt;
var dupe = opt.cloneNode(true);
s0.add(opt);
s1.add(dupe);
cnt++;
}
}
input,
select,
option {
font: inherit
}
input {
width: 4ch;
}
<form id='ui'>
<fieldset>
<legend>Enter a number in the first form field</legend>
<input id='qty0' name='qty0' type='number' min='0' max='30'>
<select id="sel0" name="sel0"></select>
<select id="sel1" name="sel1"></select>
</fieldset>
</form>
Reference
HTMLFormControlsCollection
Trying to get my second select element's options to populate from an array based on the value of the first select element. I can't seem to understand why it only populates the items from the array of the first select element. I know the appendChild is causing the items to keep tacking on at the need, but I've tried to clear the variables, but it seems the option elements that were created stay.
Any help would be great, thanks!
<select id="makeSelect" onChange="modelAppend()">
<option value="merc">Mercedes</option>
<option value="audi">Audi</option>
<option value="bmw">BMW</option>
</select>
<select id="modelSelect">
</select>
<script>
var audiModels = ["TT", "R8", "A4", "A6"]; //audimodels
var mercModels = ["C230", "B28", "LTX",]; //mercmodels
var bmwModels = ["328", "355", "458i",]; //bmwmodels
var selectedMake = document.getElementById("makeSelect"); //grabs the make select
var selectedModel = document.getElementById("modelSelect"); //grabs the model select
var appendedModel = window[selectedMake.value + "Models"]; // appends "Models" to selectedMake.value and converts string into variable
function modelAppend() {
for (var i = 0; i < appendedModel.length; i ++) { // counts items in model array
var models = appendedModel[i]; // // sets "models" to count of model array
var modelOptions = document.createElement("option"); //create the <option> tag
modelOptions.textContent = models; // assigns text to option
modelOptions.value = models; // assigns value to option
selectedModel.appendChild(modelOptions); //appeneds option tag with text and value to "modelSelect" element
}
}
</script>
This line is fishy:
var appendedModel = window[selectedMake.value + "Models"];
You need to get the element when the value has changed, not on page load. Then you need to remove the options on change too, or you will get a very long list if the user selects multiple times. Use an object to store the arrays, that makes it much easier to access them later. Also better use an event listener instead of inline js (though that's not the main problem here).
Try below code:
let models = {
audiModels: ["TT", "R8", "A4", "A6"],
mercModels: ["C230", "B28", "LTX"],
bmwModels: ["328", "355", "458i"]
}
document.getElementById('makeSelect').addEventListener('change', e => {
let el = e.target;
let val = el.value + 'Models';
let appendTo = document.getElementById('modelSelect');
Array.from(appendTo.getElementsByTagName('option')).forEach(c => appendTo.removeChild(c));
if (!models[val] || !Array.isArray(models[val])) {
appendTo.style.display = 'none';
return;
}
models[val].forEach(m => {
let opt = document.createElement('option');
opt.textContent = opt.value = m;
appendTo.appendChild(opt);
});
appendTo.style.display = '';
});
<select id="makeSelect">
<option value=""></option>
<option value="merc">Mercedes</option>
<option value="audi">Audi</option>
<option value="bmw">BMW</option>
</select>
<select id="modelSelect" style="display:none">
</select>
I am trying to make an HTML Select control display a different set of strings when clicked (or opened) than what is displayed after an item is selected. For example, when opened I want to see "one", two", "three" displayed as choices. But if the user selects two, I want "2" to be displayed as the selected item. My onclick handler reloads the Select options list with the long version of the strings and the onchange handler repopulates the control with the short strings and then re-selects the selected item. This works in Firefox, but not in IE, Safari nor Chrome. It's been almost 10 years since I last had the pleasure of coding in JavaScript. Any help would be appreciated. Here's my code:
var selectedIndex = -1;
function onChanged() {
//once selected, replace verbose with terse forms
var myList = document.getElementById("myList");
selectedIndex = myList.selectedIndex;
var optionArray = ["One|1", "Two|2", "Three|3"];
myList.options.length = 0;
for (var option in optionArray) {
var pair = optionArray[option].split("|");
var newOption = document.createElement("option");
newOption.value = pair[1];
newOption.innerHTML = pair[1];
myList.options.add(newOption);
}
myList.selectedIndex = selectedIndex;
}
function onClicked() {
var myList = document.getElementById("myList");
var optionArray = ["1|One", "2|Two", "3|Three"];
myList.options.length = 0;
for (var option in optionArray) {
var pair = optionArray[option].split("|");
var newOption = document.createElement("option");
newOption.value = pair[1];
newOption.innerHTML = pair[1];
myList.options.add(newOption);
}
if (selectedIndex > -1)
myList.selectedIndex = selectedIndex;
}
<select id="myList" onchange="onChanged()" onclick="onClicked()">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
An alternate approach would be to have each option store the full version of the text, and only change the displayed text of the selected item to the abbreviated version upon selection.
(function() {
var valueMap = {
"1": "One (1)",
"2": "Two (2)",
"11": "Eleven (11)",
"ITAR": "International Traffic in Arms Regulation (ITAR)",
"ACA": "Affordable Care Act (ACA)",
"FUBAR": "Fluffed Up Beyond All Recognition (FUBAR)"
};
var myList = document.getElementById("myList");
for (var prop in valueMap) { // populate the dropdown from our object
var opt = document.createElement("option");
opt.value = prop;
opt.text = valueMap[prop];
myList.add(opt);
}
myList.selectedIndex = -1; // nothing selected by default
myList.addEventListener("change", function() {
this.options[this.selectedIndex].text = this.options[this.selectedIndex].value;
this.blur();
});
myList.addEventListener("mousedown", function() {
if (this.selectedIndex > -1) {
var newValue = valueMap[this.options[this.selectedIndex].value];
if (this.options[this.selectedIndex].text !== newValue) {
this.options[this.selectedIndex].text = newValue;
}
}
});
})();
<select id="myList" style="width:6em"></select>
This gets you most of the way there, but still has the annoying problem that #hopkins-matt alluded to; namely that if the user opens the drop-down list and either selects the already selected item or moves off of the list without selecting anything, the selection will retain the long version of the text.
The other downside to this approach is that you need to specify the select element's width to keep it from expanding to the maximum length of its hidden option elements.
It's a timing issue.
Change:
<select id="myList" onchange="onChanged()" onclick="onClicked()">
to:
<select id="myList" onchange="onChanged()" onmousedown="onClicked()">
If the user opens the list and moves off the list without clicking, the list will not revert to original unless you call onChanged() on onmouseout as well.
<select id="myList" onchange="onChanged()" onmousedown="onClicked()" onmouseout="onChanged()">
Update: To achieve the best cross browser (onfocus is required for FF, but breaks IE) support without browser sniffing us this combination:
<select id="myList" onchange="onChanged()" onblur="onChanged()" onfocus="onClicked()" onmousedown="onClicked()">
This will also correct the second selection of the same event, but only after the user clicks away from the element.
Update:
Solved... I think.
I rewrote the function you were using to change the options. IE was not firing onchange due to you removing all the option elements and adding new option elements. Which was causing IE to not be able to reference if the user had changed the selection index. The function now just modifies the value and innerHTML of the current option elements. I am using browser sniffing to eliminate the onmouseout call for FF. FireFox was calling onmouseout if you moved the cursor to the dropdown menu. This does cause a side effect in FF. If the user selects the same option in FF, the options do not return to the original state until the onblur is fired.
Demo: http://jsfiddle.net/hopkins_matt/3m1syk6c/
JS:
function changeOptions() {
var selectedIndex = -1;
var click = 0;
var myList = document.getElementById("myList");
var optionArray = ["One|1", "Two|2", "Three|3"];
var fireFox = /Firefox/i.test(navigator.userAgent);
console.log(fireFox);
if (fireFox == false) {
myList.onmouseout=function(){changeList(false)};
}
myList.onblur=function(){changeList(false)};
myList.onchange=function(){changeList(false)};
myList.onmousedown=function(){changeList(true)};
function changeList(listOpen) {
var isListOpen = listOpen;
if (isListOpen == true) {
for (i = 0; i < myList.options.length; i++) {
var pair = optionArray[i].split("|");
myList.options[i].value = pair[0];
myList.options[i].innerHTML = pair[0];
}
}
if (isListOpen == false) {
for (i = 0; i < myList.options.length; i++) {
var pair = optionArray[i].split("|");
myList.options[i].value = pair[1];
myList.options[i].innerHTML = pair[1];
}
}
}
}
changeOptions();
HTML:
<select id="myList">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
I'm using a multiselect combobox, i select few values from the combobox and save the selected values to db. when i reopen the page, i need the focus to be placed on the values which was selected and saved.
function getSelectedValues() {
var from = document.getElementById("309127");
var to;
var v = from.options.length;
var selectedValues = "";
for (var i = 0; i < v; i++) {
if (from.options[i] && from.options[i].selected) {
var CVal = from.options[i].value;
var CText = from.options[i].text;
if (selectedValues == "") {
selectedValues = CVal;
}
else {
selectedValues = selectedValues + "~" + CVal;
}
}
}
return selectedValues;
}
this is the javascript function i used to save the selected values in db.
can anybody help me out on how to get the focus back on selected items ?
thank you
To set the focus with javascript you can use
document.getElementById("309127").focus();
For your question I'm assuming you send the values to a PHP page or something similar to update the database. If so your problem will be getting the selected values when you return to your page. Two suggestions:
Use ajax to update the database so you dont need to exit the page,
Pass the selected values back to your page through GET or similar and set the focus on page load.
EDIT: -------------
For example if you pass the values through GET like (www.example.com?param1=three)
You can use javascript to select that value on load:
<html>
<body onload="load()">
<select id="example">
<option value="one"> one </option>
<option value="two"> two </option>
<option value="three"> three </option>
</select>
</body>
<script>
function load(){
var param1 = getParameterByName("param1");
var selected = document.getElementById('example');
var opts = selected.options.length;
for (var i=0; i<opts; i++){
if (selected.options[i].value == param1){
selected.options[i].selected = true;
break;
}
}
}
function getParameterByName(name)
{
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.search);
if(results == null)
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
</script>
</html>
try var from = document.getElementById("309127");from.focus();
I want to use the value of a HTML dropdown box and create that number of input boxes underneath. I'm hoping I can achieve this on the fly. Also if the value changes it should add or remove appropriately.
What programming language would I need to do this in? I'm using PHP for the overall website.
Here is an example that uses jQuery to achieve your goals:
Assume you have following html:
<div>
<select id="input_count">
<option value="1">1 input</option>
<option value="2">2 inputs</option>
<option value="3">3 inputs</option>
</select>
<div>
<div id="inputs"> </div>
And this is the js code for your task:
$('#input_count').change(function() {
var selectObj = $(this);
var selectedOption = selectObj.find(":selected");
var selectedValue = selectedOption.val();
var targetDiv = $("#inputs");
targetDiv.html("");
for(var i = 0; i < selectedValue; i++) {
targetDiv.append($("<input />"));
}
});
You can simplify this code as follows:
$('#input_count').change(function() {
var selectedValue = $(this).val();
var targetDiv = $("#inputs").html("");
for(var i = 0; i < selectedValue; i++) {
targetDiv.append($("<input />"));
}
});
Here is a working fiddle example: http://jsfiddle.net/melih/VnRBm/
You can read more about jQuery: http://jquery.com/
I would go for jQuery.
To start with look at change(), empty() and append()
http://api.jquery.com/change/
http://api.jquery.com/empty/
http://api.jquery.com/append/
Doing it in javascript is quite easy. Assuming you've got a number and an html element where to insert. You can obtain the parent html element by using document.getElementById or other similar methods. The method assumes the only children of the parentElement is going to be these input boxes. Here's some sample code:
function addInput = function( number, parentElement ) {
// clear all previous children
parentElement.innerHtml = "";
for (var i = 0; i < number; i++) {
var inputEl = document.createElement('input');
inputEl['type'] = 'text';
// set other styles here
parentElement.appendChild(inputEl);
}
}
for the select change event, look here: javascript select input event
you would most likely use javascript(which is what jquery is), here is an example to show you how it can be done to get you on your way
<select name="s" onchange="addTxtInputs(this)" onkeyup="addTxtInputs(this)">
<option value="0">Add</option>
<option value="1">1</option>
<option value="3">3</option>
<option value="7">7</option>
</select>
<div id="inputPlaceHolder"></div>
javascript to dynamically create a selected number of inputs on the fly, based on Mutahhir answer
<script>
function addTxtInputs(o){
var n = o.value; // holds the value from the selected option (dropdown)
var p = document.getElementById("inputPlaceHolder"); // this is to get the placeholder element
p.innerHTML = ""; // clears the contents of the place holder each time the select option is chosen.
// loop to create the number of inputs based apon `n`(selected value)
for (var i=0; i < n; i++) {
var odiv = document.createElement("div"); //create a div so each input can have there own line
var inpt = document.createElement("input");
inpt['type'] = "text"; // the input type is text
inpt['id'] = "someInputId_" + i; // set a id for optional reference
inpt['name'] = "someInputName_" + i; // an unique name for each of the inputs
odiv.appendChild(inpt); // append the each input to a div
p.appendChild(odiv); // append the div and inputs to the placeholder (inputPlaceHolder)
}
}
</script>