Similar to this question here I'd like to find out how to remove duplicate options from drop down lists, however I'd like to map a list of ID's to search from and see if they have duplicate options to splice out as opposed to just one input selector.
An example of this would be as follows:
<select id="MeatList">
<option value="OBgYN7" >Ham</option>
<option value="ELmn5">Beef</option>
<option value="KrUKt6">Chicken</option>
<option value="OBgYN7" selected="selected">Ham</option>
</select>
<select id="Seats">
<option value="2" >Table For Two</option>
<option value="3">Table For Three</option>
<option value="5">Table for Five</option>
<option value="10" >Party Table</option>
</select>
<select id="Lastname">
<option value="Tao" >The Tao's</option>
<option value="Smith">The Smith's</option>
<option value="Samuels">The Samuels'</option>
<option value="Smith" >The Smith's</option>
</select>
As you can see, the inputs MeatList and Lastname have duplicate values, I want to be able to search all drop down boxes for duplicate values (or inner text) and splice them out. Would that be possible through mapping of some sort?
The code to be used would be:
[].slice.call(fruits.options)
.map(function(a){
if(this[a.innerText]){
if(!a.selected) fruits.removeChild(a);
} else {
this[a.innerText]=1;
}
},{});
And to get an idea of what I mean by mapping the drop-down lists, I would use a code like this:
var idlist= ["MeatList", "Seats", "Lastname"];
var handlelists = idlist.join("|");
[].slice.call(handlelists.options)
.map(function(a){
if(this.search([a.innerText])){
if(!a.selected) handlelists.removeChild(a);
} else {
this[a.innerText]=1;
}
},{});
Not sure what you thought was going on in the handleLists part of your script. You just need to wrap the other segment in an iterator (forEach) after finding the elements corresponding to the IDs.
var idList= ["MeatList", "Seats", "Lastname"].map(function(id){return document.getElementById(id)});
idList.forEach(function(select){
[].slice.call(select.options)
.map(function(a){
if(this[a.value]){
select.removeChild(a);
} else {
this[a.value]=1;
}
},{});
});
Of course, this is bad. You should make de-duplicating a function of it's own, eg.:
function deDuplicate(select){
[].slice.call(select.options)
.map(function(a){
if(this[a.value]){
select.removeChild(a);
} else {
this[a.value]=1;
}
},{});
}
and then:
var idList= ["MeatList", "Seats", "Lastname"].map(function(id){return document.getElementById(id)});
idList.forEach(function(select){ deDuplicate(select); });
Personally I recommend learning/using CoffeeScript as it uncrufts Javascript a great deal, the de-dupe looks like this:
deDuplicate = (select)->
[].slice.call(select.options).map (a)->
if #[a.value]
select.removeChild a
else
#[a.value] = 1
, {}
and then wrapped you can do:
deDuplicate select for select in ["MeatList", "Seats", "Lastname"].map (id)->
document.getElementById id
Which reads more plainly as english, at least to me it does. As always YMMV.
Related
I would like to set an option in a select element based on the substring which will be contained in one of the option values. I have a solution but it seems quite convoluted to me.
I get the values of the options and put them in an array, loop through the values and check if the value includes a string I am looking for when it does I set that value as the select value. There must be an easier way!
I get the values of the options in the following way.
// Get the select element where you can select a procinve with a pull-down
var provincePullDown = document.querySelector(".select-provincie");
// Array containing the values of the select options
var optArray = Array.from(provincePullDown.options);
var optArrayValues = [];
optArray.forEach(el => optArrayValues.push(el.value));
I then loop over the values looking with a likely substring.
// Loop over the values in the select options
optArrayValues.forEach(function (el) {
// Look for the option containing the right province
if (el.includes(selectedProvince)) {
// Set the selected option from the select element
provincePullDown.value = el;
}
});
The option values look something like this sting (3) and the substring like this string.
I would like to know if there is an easier way as to me this seems an overly convoluted solution. And keeping maintenance in mind I would like an clear solution that I will still easily understand in 6 months.
The page is created by Drupal so I also control what html is outputted and the option values are inserted in the Drupal template.
Let me also state that I am not a fan of jQuery even though the project does load jQuery by default.
As querySelector() support any valid CSS selector, you can try with contains (*=) Attribute selector:
[attr*=value]
Represents elements with an attribute name of attr whose value contains at least one occurrence of value within the string.
var selectedProvince = 'province';
document.querySelector(".select-provincie option[value*='"+selectedProvince+"']").selected = true;
<select class="select-provincie">
<option value="prov-1">Province 1</option>
<option value="prov-2">Province 2</option>
<option value="province-test">Province 3</option>
<option value="prov-3">Province 4</option>
</select>
You can also use Template Literals for cleaner syntax:
var selectedProvince = 'province';
document.querySelector(`.select-provincie option[value*='${selectedProvince}']`).selected = true;
<select class="select-provincie">
<option value="prov-1">Province 1</option>
<option value="prov-2">Province 2</option>
<option value="province-test">Province 3</option>
<option value="prov-3">Province 4</option>
</select>
You can directly point to the option value if the regext is just a simple contain
const optToSelect = document.querySelector('option[value*=${SUBSTRING}]');
document.querySelector("select").selectedIndex = optToSelect.index;
You can use plain DOM methods with find and includes:
function updateOther(source) {
let value = source.value;
let sel = document.querySelector('.select-provincie');
sel.selectedIndex = [].find.call(sel.options, opt => opt.value.includes(value)).index;
}
<select onchange='updateOther(this)'>
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<select class="select-provincie">
<option value="province1" selected>Province 1</option>
<option value="province2">Province 2</option>
<option value="province3">Province 3</option>
<option value="province4">Province 4</option>
</select>
But it's not fault tolerant: if a suitable value isn't found, it will throw an error (as do other answers). :-)
JQuery is interesting precisely when you want simplify solutions and ensure it is practical in terms of optimization. So I want to bring you a JQuery solution.
var selectedProvince = 'province3';
$(".select-provincie > option").each((index, elem) => {
if (elem.value == selectedProvince) {$(elem).attr('selected', true)};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="select_provincie">
<select class="select-provincie">
<option value="province1">Province 1</option>
<option value="province2">Province 2</option>
<option value="province3">Province 3</option>
<option value="province4">Province 4</option>
</select>
</div>
Based on this useful topic Use jQuery to change a second select list based on the first select list option I try to adapt the code for my purposes.
My problem is that for some reasons I cannot have the exact same integer values in my 2 selection. I only can provide something close as:
<select name="select1" id="dropDown">
<option value="fruit">Fruit</option>
<option value="animal">Animal</option>
<option value="bird">Bird</option>
<option value="car">Car</option>
</select>
<select name="select2" id="dropDown_2">
<option value="fruit-01">Banana</option>
<option value="fruit-02">Apple</option>
<option value="fruit-03">Orange</option>
<option value="animal-01">Wolf</option>
<option value="animal-02">Fox</option>
<option value="animal-03">Bear</option>
<option value="bird-01">Eagle</option>
<option value="bird-02">Hawk</option>
<option value="car-01">BMW<option>
</select>
The js to be modified is:
$("#dropDown").change( function() {
if ( $(this).data('options') == undefined ) {
/*Taking an array of all options-2 and kind of embedding it on the select1*/
$(this).data( 'options', $("#dropDown_2").find('option').clone() );
}
var id = $(this).val();
var options = $(this).data('options').filter('[value=' + id + ']');
$("#dropDown_2").html(options);
} );
I know that there are some js techniques to subtract substrings and similar stuff. But my skills are not so good to exactly say how. Is there anyone willing to help me? I need to filter the second options with its values based (but not identical) on the values of the first. Hope I explained myself sufficiently. Many many thanks!
EDIT
First of all sorry for not explaining myself sufficiently. I have to add that I cannot change the markUp!
So I inserted an each loop before the code that Shiran kindly delivered me to prepare it like so:
$("#dropDown_2").find('option').each( function() {
var $this = $(this);
var val = $this.val();
var myFilter = val.slice(0,-3)
$this.addClass( myFilter );
// $this.data('filter', myFilter ); does not work don’t know why
} );
Which seems to work at least in principle. Yet, for reasons that remain obscure for me sadly my attempt to attach data-filter to my option elements wasn’t accepted. So I had to go for classes which worked (at least for the loop).
I then tried to modify the code ending up with the following:
$("#dropDown").change(function() {
var filters = [];
if ($(this).attr('class') == "") {
$(this).find("option").each(function(index, option) {
if ($(option).attr('class') != "")
filters.push($(option).attr('class'));
} );
} else {
filters.push($(this).attr('class'));
}
$("#dropDown_2").html("");
$.each(filters, function(index, value) {
$options.find("option." + value ).clone().appendTo($("#dropDown_2"));
} );
} );
But as you can guess this didn’t work. :-(
And I also noted that the values of my filter array are the class (would be analogue to the filter value in the original) of my select not of the options of it. But obviously Shorans code did work well. What did I wrong here?
Please help, I am getting grey hair with this!! Thanks so much in advance!
$(this).data("options") gets:
<select data-options="the data here"> ==> "the data here"
Here's a working version:
(notice how I used data-filter in the second select and in the last each loop in the javascript part)
$(document).ready(function() {
var $options = $("#dropDown_2").clone(); // this will save all initial options in the second dropdown
$("#dropDown").change(function() {
var filters = [];
if ($(this).val() == "") {
$(this).find("option").each(function(index, option) {
if ($(option).val() != "")
filters.push($(option).val());
});
} else {
filters.push($(this).val())
}
$("#dropDown_2").html("");
$.each(filters, function(index, value) {
$options.find("option").each(function(optionIndex, option) { // a second loop that check if the option value starts with the filter value
if ($(option).val().startsWith(value))
$(option).clone().appendTo($("#dropDown_2"));
});
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select name="select1" id="dropDown">
<option value="">All</option>
<option value="fruit">Fruit</option>
<option value="animal">Animal</option>
<option value="bird">Bird</option>
<option value="car">Car</option>
</select>
<select name="select2" id="dropDown_2">
<option value="fruit-01">Banana</option>
<option value="fruit-02">Apple</option>
<option value="fruit-03">Orange</option>
<option value="animal-01">Wolf</option>
<option value="animal-02">Fox</option>
<option value="animal-03">Bear</option>
<option value="bird-01">Eagle</option>
<option value="bird-02">Hawk</option>
<option value="car-01">BMW
<option>
</select>
Currently I am working on a site where I do not have access to the perl generated options of a drop down list. The drop downs are populated dynamically and not all options are available to all users.
The code I am able to work with is shown here.
<select class="fielddrop" name="PRIMARY_POS" size="1" style="width: 187px;" ></select>
PRIMARY_POS
populates each option that is able to be selected.
The actual output as seen when the page renders is
<select class="fielddrop" name="PRIMARY_POS" size="1" style="width: 187px;">
<option value="0">None Selected
<option value="155935">Option4
<option value="155934">Option3
<option value="155905">Option2
<option value="155933">Option1
<option value="155932">Option5
</select>
What I need to be able to do is set a sort order based on a hidden attribute that is assigned based on the text value
So in the above example. I need the drop downs ( Important as their are mulitple drop downs on the page ) to be able to be sorted by a not yet created attribute
So that the above code might then be
<option value="0">None Selected
<option sortvalue="5" value="155935">Option4
<option sortvalue="4" value="155934">Option3
<option sortvalue="3" value="155905">Option2
<option sortvalue="2" value="155933">Option1
<option sortvalue="1" value="155932">Option5
</select>
The sortvalue being set base don the Text value of the option select. So that a sortvalue of 5 would be assign to Option4. Just a smaple as the text will need to be assigned.
End result should be that the Drop down list now has a custom attribute of Sortvalue and the select drop down is now sorted by that value.
Once again, I can not directly change the attributes but can manipulate the results. Hope that was easy to follow, which I doubt :/
You can create an object where the keys are the text and values are sort order. Then loop over options and add attribute based on that map
var optsMap = {
"Option4": 5,
"Option5": 1
......
};
var $select = $('select[name=PRIMARY_POS]')
$select.find('option').attr('data-sortvalue', function(){
return optsMap[$(this).text()] ||0;
}).sort(function(a,b){
return +($(a).data('sortvalue')||0) - +($(b).data('sortvalue')||0);
}).appendTo($select);
You can then read the value using:
$select.change(function(){
alert($(this).find(':selected').data('sortvalue'));
})
If all you are needing is sorting and don't need attribute can remove one step
DEMO
Common practice is to prefix those "added attributes" with data. You could try something like this with jQuery, if I'm understanding you correctly.
Example fiddle: https://jsfiddle.net/30cvudz8/7/
<select class="my-select">
<option data-sort-value="3" value="1">Option 1</option>
<option data-sort-value="5" value="2">Option 2</option>
<option data-sort-value="4" value="3">Option 3</option>
<option data-sort-value="1" value="4">Option 4</option>
<option data-sort-value="2" value="5">Option 5</option>
</select>
var optionList = new Array();
$('select.my-select option').each(function() {
optionList[optionList.length] = $(this).attr('data-sort-value')+'::'+$(this).val();
});
optionList.sort(); // sort it
var newOptionList = '';
for(var i = 0; i < optionList.length; i++) {
// recreate option
var parts = optionList[i].split('::');
newOptionList += '<option value="'+parts[1]+'" data-sort-value="'+parts[0]+'">Option '+parts[1]+'</option>';
}
// wipe and repopulate the select list
$('select.my-select').html(newOptionList);
To add an attribute (like data-sort-value) after you have a select list, you can do something like this:
$('select.original option').each(function() {
var sortingValue = getSortingValueFromText($(this).text());
$(this).attr('data-sort-value', sortingValue);
});
I have an issue with the data which is sent from a drop down menu, the selector only returns a single value, even when multiple values are selected. I have searched online for a solution to this, but they all use PHP, JQuery or some method outside the scope of the course I am taking; to capture multiple selected items. I have tried .value of the individual options, but that returns all of the options rather than just the ones which are selected. Is there some kind of trick to sending multiple values?
Here is my code for the menu. For example If I select JAVA PROGRAMMING, NETWORKS and VIDEO GAMES, only JAVA PROGRAMMING is sent.
<select multiple id="CK_Expertise">
<option id="CK_Exp1" value="Java programming">JAVA PROGRAMMING</option>
<option id="CK_Exp2" value="Networks">NETWORKS</option>
<option id="CK_Exp3" value="Video game programming">VIDEO GAMES</option>
<option id="CK_Exp4" value="Accounter">ACCOUNTER</option>
<option id="CK_Exp5" value="Help Desk">HELPDESK</option>
<option id="CK_Exp6" value="C++ programming">C++</option>
<option id="CK_Exp7" value="Programming">PROGRAMMING</option>
</select>
I have also tried using the Select Object in the DOM, http://www.w3schools.com/jsref/dom_obj_select.asp
which has a few methods for accessing the options in the dropdown menu. One method in particular called selectedIndex, seemed to be what I am looking for, however it only returns the the index of the first selected option, instead of all of the selected options.
Is there a simple solution to this using just Javascript and the DOM?
Thanks
- Chris
Get the options, iterate and check if they are selected, and add the values to an array
var select = document.getElementById('CK_Expertise'),
options = select.getElementsByTagName('option'),
values = [];
for (var i=options.length; i--;) {
if (options[i].selected) values.push(options[i].value)
}
console.log(values)
FIDDLE
or being a little more fancy
var select = document.getElementById('CK_Expertise'),
values = Array.prototype.filter.call(select.options, function(el) {
return el.selected;
}).map(function(el) {
return el.value;
});
console.log(values)
FIDDLE
You could use the select.selectedOptions property:
select.onchange = function() {
var values = [].map.call(this.selectedOptions, function(opt){
return opt.value;
});
};
document.getElementById('CK_Expertise').onchange = function() {
document.querySelector('pre').textContent = JSON.stringify([].map.call(
this.selectedOptions, function(opt){ return opt.value; }
));
}
<select multiple id="CK_Expertise">
<option id="CK_Exp1" value="Java programming">JAVA PROGRAMMING</option>
<option id="CK_Exp2" value="Networks">NETWORKS</option>
<option id="CK_Exp3" value="Video game programming">VIDEO GAMES</option>
<option id="CK_Exp4" value="Accounter">ACCOUNTER</option>
<option id="CK_Exp5" value="Help Desk">HELPDESK</option>
<option id="CK_Exp6" value="C++ programming">C++</option>
<option id="CK_Exp7" value="Programming">PROGRAMMING</option>
</select>
<pre></pre>
If you can use jQuery, this will give you all the values
$(document).ready(function(){
$('#CK_Expertise').change(function(e){
var values = $('#CK_Expertise').val()
alert(values);
});
});
HTH,
-Ted
You could iterate storing select.selectedIndex in an array and unselecting the corresponding option to get the next one:
select.onchange = function() {
var i, indices=[], values = [];
while((i=this.selectedIndex) > -1) {
indices.push(i);
values.push(this.value);
this.options[i].selected = false;
}
while((i=indices.pop()) > -1)
this.options[i].selected = true;
console.log(values);
}
Demo
This way you avoid iterating over all options, but you must iterate twice over the selected ones (first to unselect them, them to select them again).
Why not using an indexed variable in the SELECT command?
<SELECT MULTIPLE id="stuff" name="stuff[]">
<OPTION value=1>First stuff</option>
<OPTION value=2>Second stuff</option>
<OPTION value=3>Third stuff</option>
</SELECT>
In that case it's easy to read the array:
$out=$_REQUEST['stuff'];
foreach($out AS $thing) {
echo '<br />'.$thing;
}
Sorry for the poor indentation, but I just wanted to show the way I use for solving this case!
var select = document.getElementById('CK_Expertise'),
options = select.selectedOptions,
values = [];
for(let i=0;i<options.length;i++)
{
values.push(options[i].value);
}
console.log(values);
i am using javascript to get the text of selected item from dropdown list.
but i am not getting the text.
i am traversing the dropdown list by name..
my html dropdownlist is as:
<select name="SomeName" onchange="div1();">
<option value="someVal">A</option>
<option value="someOtherVal">B</option>
<option value="someThirdVal">C</option>
</select>
and my javascript is as:
function div1() {
var select = document.getElementsByName("SomeName");
var result = select.options[select.selectedIndex].text;
alert(result);
}
can you please help me out..
Option 1 - If you're just looking for the value of the selected item, pass it.
<select name="SomeName" onchange="div1(this.value);">
<option value="someVal">A</option>
<option value="someOtherVal">B</option>
<option value="someThirdVal">C</option>
</select>
function div1(val)
{
alert(val);
}
Option 2 - You could also use the ID as suggested.
<select id="someID" name="SomeName" onchange="div1();">
<option value="someVal">A</option>
<option value="someOtherVal">B</option>
<option value="someThirdVal">C</option>
</select>
function div1()
{
var ddl = document.getElementById("someID");
var selectedText = ddl.options[ddl.selectedIndex].value;
alert(selectedText);
}
Option 3 - You could also pass the object itself...
<select name="SomeName" onchange="div1(this);">
<option value="someVal">A</option>
<option value="someOtherVal">B</option>
<option value="someThirdVal">C</option>
</select>
function div1(obj)
{
alert(obj.options[obj.selectedIndex].value);
}
getElementsByName returns an array of items, so you'd need:
var select = document.getElementsByName("SomeName");
var text = select[0].options[select[0].selectedIndex].text;
alert(text);
Or something along those lines.
Edit: instead of the "[0]" bit of code, you probably want either (a) to loop all items in the "select" if you expect many selects with that name, or (b) give the select an id and use document.getElementById() which returns just 1 item.
The problem with the original snippet posted is that document.getElementsByName() returns an array and not a single element.
To fix the original snippet, instead of:
document.getElementsByName("SomeName"); // returns an array
try:
document.getElementsByName("SomeName")[0]; // returns first element in array
EDIT: While that will get you up and running, please note the other great alternative answers here that avoid getElementsByName().