Javascript: dropdown, get first element value LIKE? - javascript

Given a dropdown with an unknown number of option elements:
<select id="ddlDropDown">
<option value="text1">Some text</option>
<option value="text2">Some text</option>
<option value="text3">Some text</option>
...
<option value="textN">Some text</option>
And given a textbox where I can type in a value:
<input type=text id="txtTextBox" onkeyup="selectDDL();"/>
And given the script function:
function selectDDL(){
var txtElem = document.getElementById("txtTextBox");
var ddlElem = document.getElementById("ddlDropDown");
var typedText = txtElem.value;
//magic happens here
}
How do I, using purely javascript, get select the first option matching LIKE the text in the text box without iterating through the entire collection?
That is to say, assume that I have 500 dropdown option elements with random values between 500 and 1500, how do I get and select the first option (in the list, not in order) that matches what the user has typed so far?
So if their were three items: 1030, 1012, and 1013 in the dropdown and the user types:
1: 1030 is selected.
10: 1030 is still selected
101: 1012 is selected
1013: 1013 is selected
Clarification: without iterating the collection and similar to jquery's ^= operator

You don't need jQuery to use ^=, just use querySelectorAll with the attribute prefix selector:
var texts = document.querySelectorAll("[value^='text']");
console.log(texts);
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
<select id="ddlDropDown">
<option value="text1">Some text</option>
<option value="text2">Some text</option>
<option value="text3">Some text</option>
<option value="textN">Some text</option>
<option value="notText">123456</option>
</select>

You can use a starts with attribute selector. Only issue with the code is I am not escaping any of the special characters from the selector. So if the user enters in ' it will blow up.
document.querySelector("#x").addEventListener("keyup", function(){
//code to filter out the options
var txt = this.value;
var opts = document.querySelectorAll("#ddlDropDown option[value^='" + txt + "']");
//code to display the options for demo
var out = Array.prototype.slice.call( opts ).map(function (x) {return x.value});
document.querySelector("p").innerHTML = out.join("<br/>");
});
<select id="ddlDropDown">
<option value="text1">Some text</option>
<option value="text2">Some text</option>
<option value="text3">Some text</option>
<option value="text11">Some text</option>
<option value="text21">Some text</option>
<option value="text31">Some text</option>
</select>
<input type="textbox" id="x">
<p></p>

I would use the string#indexOf method to find out if there's a match.
function selectDDL() {
var txtElem = document.getElementById("txtTextBox");
var ddlElem = document.getElementById("ddlDropDown");
var typedText = txtElem.value;
var options = document.querySelectorAll("#ddlDropDown option");
var matches = [];
for (var i = 0; i < 3; i++) {
if (options[i].innerHTML.indexOf(typedText) == 0) {
matches.push(options[i]);
}
}
matches[0].setAttribute("selected", "selected");
}

Those who rely on a selector with [value^=...] will find an option by its value attribute, not by its text.
There is no CSS selector for selecting an option by its text. jQuery supports "has" and "contains", but uses iteration to implement those features.
Just for a fun alternative, but probably not advisable: innerHTML is slow and this will go wrong when the select tag has other tags inside than the options:
var html = ddlElem.innerHTML;
var idx = html.indexOf('>'+typedText);
ddlElem.selectedIndex = idx === -1
? -1
: html.substr(0, idx).match(/\<option/g).length - 1;

Related

Two dynamic select boxes with data attribute in both and dependant on them

How to get dynamic select boxes dependant on the value of data attributes in both?
Got this code
HTML
<select id="hours" onchange="giveSelection()">
<option value="somethingA" data-option="1">optionA</option>
<option value="somethingB" data-option="2">optionB</option>
</select>
<select id="paxno">
<option data-option="1">optionC</option>
<option data-option="1">optionD</option>
<option data-option="2">optionE</option>
<option data-option="1">optionF</option>
</select>
JS
var sel1 = document.querySelector('#hours');
var sel2 = document.querySelector('#paxno');
var options2 = sel2.querySelectorAll('option');
function giveSelection() {
sel2.innerHTML = '';
for(var i = 0; i < options2.length; i++) {
if(options2[i].dataset.option === $("#hours").find(":selected").data("option")) {
sel2.appendChild(options2[i]);
}
}
}
I have been trying to do this from the example given on this question on Stackoverflow, and it is working when data-attribute is non numeric but data stored in both will be numeric.
Any thoughts what I am doing wrong here? is this the best approach to 2 dynamic select boxes with both having data attributes?
Since you're using jQuery, you might as well use it all the way.
To make it consistent, always use the jQuery data() method. data() will always try to intelligently convert the value of the data field to another type if it can determine that it is a number, or an object, or an array, or etc. So your original was comparing a dataset.option to a data(), using === which removes type coersion. So nothing would ever be equal.
var sel1 = $('#hours');
var sel2 = $('#paxno');
var options2 = sel2.find('option');
function giveSelection() {
var target = sel1.find(':selected').data('option');
sel2.empty().append(
options2.filter(function(){
return $(this).data('option') === target;
})
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="hours" onchange="giveSelection()">
<option value="somethingA" data-option="1">optionA</option>
<option value="somethingB" data-option="2">optionB</option>
</select>
<select id="paxno">
<option data-option="1">optionC</option>
<option data-option="1">optionD</option>
<option data-option="2">optionE</option>
<option data-option="1">optionF</option>
</select>

Remove the duplicate values and combinations in html select option

I have a dynamically generated <select> field with <option>.
<select>
<option value=""></option>
<option value=""></option>
<option value=""> False</option>
<option value=""> True</option>
<option value="">False False</option>
<option value="">False True</option>
<option value="">True</option>
<option value="">True True</option>
</select>
I would like to remove the duplicate occurrences and combinations. The final <select> field with <option> should look like :
<select>
<option value=""></option>
<option value="">False</option>
<option value="">True</option>
</select>
Here is how my fiddle looks like. Been trying to solve this for hours.
var values = [];
$("select").children().each(function() {
if (values.length > 0) {
var notExists = false;
for (var x = 0; x < values.length; x++) {
var _text = this.text.replace(/\s/g, "");
var value = values[x].replace(/\s/g, "");
if (values[x].length > _text.length) {
//console.log('>>+', value, ' || ', _text, value.indexOf(_text))
notExists = value.indexOf(_text) > -1 ? true : false;
} else {
//console.log('>>*', value, ' || ', _text, _text.indexOf(value))
notExists = _text.indexOf(value) > -1 ? true : false;
}
}
if (notExists) {
//this.remove();
values.push(this.text);
}
} else {
values.push(this.text);
}
});
Any help to solve this is appreciated.
You can use map() to return all options text and use split() on white-space. Then to remove duplicates you can use reduce() to return object. Then you can empty select and use Object.keys() to loop each property and append to select.
var opt = $("select option").map(function() {
return $(this).text().split(' ')
}).get();
opt = opt.reduce(function(o, e) {return o[e] = true, o}, {});
$('select').empty();
Object.keys(opt).forEach(function(key) {
$('select').append(' <option value="">'+key+'</option>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select>
<option value=""></option>
<option value=""></option>
<option value="">False</option>
<option value="">True</option>
<option value="">False False</option>
<option value="">False True</option>
<option value="">True</option>
<option value="">True True</option>
</select>
You can loop through each of this children text , then use substring to get the first text & put it in an array.
Once done empty the select element and append the newly created options
var _textHolder=[]; // NA empty array to hold unique text
var _options="";
$("select").children().each(function(item,value) {
var _textVal = $(this).text().trim(); // Remove white space
//get the first text content
var _getText = _textVal.substr(0, _textVal.indexOf(" "));
// if this text is not present in array then push it
if(_textHolder.indexOf(_getText) ==-1){
_textHolder.push(_getText)
}
});
// Create new options with items from _textHolder
_textHolder.forEach(function(item){
_options+='<option value="">'+item+'</option>'
})
// Empty current select element and append new options
$('select').empty().append(_options);
JSFIDDLE
I would do with pure JS ES6 style. This is producing a words array from the whitespace separated options element's innerText value regardless the words are in the front, middle or the end; and it will create a unique options list from that. Basically we are concatenating these arrays and getting it unified by utilizing the new Set object. The code is as follows;
var opts = document.querySelector("select").children,
list = Array.prototype.reduce.call(opts, function(s,c){
text = c.innerText.trim().split(" ");
return new Set([...s].concat(text)) // adding multiple elements to a set
},new Set());
list = [...list]; // turn set to array
for (var i = opts.length-1; i >= 0; i--){ //reverse iteration not to effect indices when an element is deleted
i in list ? opts[i].innerText = list[i]
: opts[i].parentNode.removeChild(opts[i]);
}
<select>
<option value=""></option>
<option value=""></option>
<option value=""> False</option>
<option value=""> True</option>
<option value="">False False</option>
<option value="">False True</option>
<option value="">True</option>
<option value="">True True</option>
</select>

How to fill and add text in a text field with drop down selections

I'm not a coder ut I've found this code here
http://jsfiddle.net/kjy112/kchRh/
<textarea id="mytext"></textarea>
<select id="dropdown">
<option value="">None</option>
<option value="text1">text1</option>
<option value="text2">text2</option>
<option value="text3">text3</option>
<option value="text4">text4</option>
</select>
var mytextbox = document.getElementById('mytext');
var mydropdown = document.getElementById('dropdown');
mydropdown.onchange = function(){
mytextbox.value = mytextbox.value + this.value;
}
I'd like to modify it so that I've more than one dropdown and each one add his text in the same field.
Practically I'd have to create a compact code easily for the user so that the user select some phrases using the dropdown and the code will fill the text field.
If I can be more precise please let me know. As said Iìm not a coder so if you can write down the code to use I'll be very happy.
Thanks!
Here's a js bin with multiple dropdowns' onchange event being listed to: https://jsfiddle.net/kchRh/944/
You want to give the dropdowns class names and then loop through each drop down to setup their listeners.
HTML:
<textarea id="mytext"></textarea>
<select class="dropdown">
<option value="">None</option>
<option value="text1">text1</option>
<option value="text2">text2</option>
<option value="text3">text3</option>
<option value="text4">text4</option>
</select>
<select class="dropdown">
<option value="">2None</option>
<option value="2text1">2text1</option>
<option value="2text2">2text2</option>
<option value="2text3">2text3</option>
<option value="2text4">2text4</option>
</select>
JS:
var mytextbox = document.getElementById('mytext');
var mydropdowns = document.getElementsByClassName('dropdown');
for(i=0;i<mydropdowns.length;i++) {
mydropdowns[i].onchange = function(){
mytextbox.value = mytextbox.value + this.value;
}
}
I'd suggest the following approach:
// create a reusable function:
function updateTextArea() {
// get all the elements with the class 'dropdown':
var selectElems = document.querySelectorAll('.dropdown'),
// get the <textarea> element, using its id:
textArea = document.getElementById('mytext'),
// using Array.prototype.filter on the array-like
// NodeList, using Function.prototype.call, in
// order to iterate over the found '.dropdown'
// elements to form an array of only those elements
// with a non-zero-length value:
values = Array.prototype.filter.call(selectElems, function(el) {
if (el.value.trim().length) {
return el.value;
}
// iterating over the filter-created array, to form a map of
// the selected values of the elements:
}).map(function(el) {
return el.value;
// joining those arrays together, with Array.prototype.join,
// to form a comma-separated string of values, and appending
// a period:
}).join(', ') + '.';
// setting the value of the <textarea> to:
// - an empty string (if the values variable is
// just the appended-period), or to the value of
// the values variable:
textArea.value = values === '.' ? '' : values;
}
// as above, retrieving the '.dropdown' elements:
var selects = document.querySelectorAll('.dropdown');
// iterating over the '.dropdown' elements, using
// Array.prototype.forEach:
Array.prototype.forEach.call(selects, function(el, index, arr) {
// within the anonymous function of Array.prototype.foreach:
// the first argument (here: 'el') is the current array-element,
// second argument (here: 'index') is the index of the current
// array-element within the array over which we're iterating,
// third argument (here: 'arr') is the array over which we're
// iterating.
// binding updateTextArea as the change event-handler for
// each of the array-elements over which we iterate:
el.addEventListener('change', updateTextArea);
});
function updateTextArea() {
var selectElems = document.querySelectorAll('.dropdown'),
textArea = document.getElementById('mytext'),
values = Array.prototype.filter.call(selectElems, function(el) {
if (el.value.trim().length) {
return el.value;
}
}).map(function(el) {
return el.value;
}).join(', ') + '.';
textArea.value = values === '.' ? '' : values;
}
var selects = document.querySelectorAll('.dropdown');
Array.prototype.forEach.call(selects, function(el) {
el.addEventListener('change', updateTextArea);
});
<textarea id="mytext"></textarea>
<select class="dropdown">
<option value="">None</option>
<option value="text1">text1</option>
<option value="text2">text2</option>
<option value="text3">text3</option>
<option value="text4">text4</option>
</select>
<select class="dropdown">
<option value="">None</option>
<option value="text5">text5</option>
<option value="text6">text6</option>
<option value="text7">text7</option>
<option value="text8">text8</option>
</select>
JS Fiddle demo.
Note, in the HTML, I've changed from the use of id to identify the <select> elements, to using class; simply because it allows a group of elements to be associated together without having to use a large number of ids and subsequently having to update the JavaScript in turn with the HTML.
Referencs:
Array.prototype.filter().
Array.prototype.forEach().
Array.prototype.join().
Array.prototype.map().
document.querySelectorAll().
eventTarget.addEventListener().
Function.prototype.call().

Display items of two drop down based on each other

I have two drop downs with exactly the same values.
I want the drop down 2 to display the values based on the selection of items of drop down 1.
So the selected index of drop down 2 will be equal to or more than the selected index of drop down 1.
document.getElementById("SELECTB").selectedIndex >= document.getElementById("SELECTA").selectedIndex
So if B is selected in Drop down 1 then selectable options in drop down 2 will be B,C and D. (A will be not selectable item)
http://jsfiddle.net/xxyhm78t/1/
Solution working with pure Javascript:
var select1 = document.getElementById("SELECTA");
var select2 = document.getElementById("SELECTB");
select1.onchange = function () {
while (select2.firstChild) {
select2.removeChild(select2.firstChild);
}
for (var i = select1.selectedIndex; i < select1.options.length; i++) {
var o = document.createElement("option");
o.value = select1.options[i].value;
o.text = select1.options[i].text;
select2.appendChild(o);
}
}
Fiddle
Reference: This is an adjusted solution from javascript Change the Dropdown values based on other dropdown
Update: Like asked in the comment - to disable the options instead of removing them:
var select1 = document.getElementById("SELECTA");
var select2 = document.getElementById("SELECTB");
select1.onchange = function () {
while (select2.firstChild) {
select2.removeChild(select2.firstChild);
}
for (var i = 0; i < select1.options.length; i++) {
var o = document.createElement("option");
o.value = select1.options[i].value;
o.text = select1.options[i].text;
(i <= select1.selectedIndex)
? o.disabled = true
: o.disabled = false ;
select2.appendChild(o);
}
}
Adjusted Fiddle
Update 2: Like asked in the comment if it's possible to adjust this to use class names instead of ids - yes, by using getElementsByClassName(). I've adjusted in this Fiddle both selects to have class="SELECTA" and class="SELECTB" instead of the previously used id. The according adjustment for the Javascript is only the declaration of the variables:
var select1 = document.getElementsByClassName("SELECTA")[0];
var select2 = document.getElementsByClassName("SELECTB")[0];
As you already know, an id is a unique attribute, therefore it's possible to get a single element using getElementById(). getElementsByClassName() returns a collection of HTML elements instead, even if there's only a single element having the class. So it's - in this example - necessary to address the 1st element of this collection. As counting starts by 0, the first (and only) element having the class "SELECTA" is getElementsByClassName("SELECTA")[0].
Reference: https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName#Syntax
You can do this using selectedIndex with the following piece of code:
$("#SELECTA").change(function() {
var selIndex = this.selectedIndex;
$("#SELECTB").find("option").each(function(k,v) {
$(this).attr("disabled", selIndex > k);
});
});
Depending on what it is you are after, you may need to reset #SELECTB if one of the disabled values is selected.
I think this is what you are looking for:
$("select").on("change", function (e) {
var sel = this.selectedIndex;
$("#SELECTB option").each(function (i, e) {
$(this).prop("disabled", sel > i);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="SELECTA">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>
<select id="SELECTB">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>
And this can be even more general:
$("select").on("change", function (e) {
var sel = this.selectedIndex;
var nextSelect = $(this).parent().find("select").not(this);
$(nextSelect).children().each(function (i, e) {
$(this).prop("disabled", sel > i);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="SELECTA">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>
<select id="SELECTB">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>

Chosen select box with multiple selected values on page load

I'm trying to select multiple values on page load, but it only selects the last value on the array. Take a look at the code
jQuery("#language").chosen();
var str = '12,24,36';
var languageArray = str.split(',');
for (var i = 0; i < languageArray.length; i++) {
jQuery("#language").val(languageArray[i]);
jQuery("#language").trigger("liszt:updated");
}
I get only 36 selected on page load, is there anything wrong with the js ?
Here is the HTML for the select
<select name="language[]" id="language" data-placeholder="Choose Language..." multiple="multiple">
I appreciate your help.
Thanks
You can select multiple options in a multi-value select box by passing an array to the val() method.
Example
Markup
<select name="language" id="language" data-placeholder="Choose Language..." multiple="multiple">
<option value="en">English</option>
<option value="fr">French</option>
<option value="de">German</option>
</select>
JavaScript
var str = 'en,de';
jQuery("#language").val(str.split(','));
And here's a jsFiddle for funsies.
you could set the selected property of matched option element. hope it would help.
var values = ['1', '2', '4'];
$('#languages').find('option').filter(function (idx, option) {
if($.inArray(option.value, values) !== -1) {
return option;
}
}).prop('selected', 'true');

Categories