Javascript - IE11 - void results with querySelectAll() - javascript

I have an issue with a simple js function on IE (11 and lower). When I use document.querySelector('#id').querySelectorAll('option') where #id is linked to a element, it return an array of options, but "void" like
<option id="id"></options>
my very simple JS :
var projectsList = document.querySelector('#taskproject').querySelectorAll('option');
console.dirxml(projectsList);
and my HTML code (an exemple) :
<select id="taskproject" name="newproject">
<option id="1">Project1</option>
<option id="2">Project2</option>
[...]
<option id="99">Project99</option>
</select>
This will return, with the console.dirxml function in the IE11 console
<NodeList lenght="99">
<option id="1"></option>
[....]
<option id="99"></option>
</NodeList>
This works on chrome, the text inside options is written on the console.
Thanks for your help!
Edit with runnable example
var projectsList = document.querySelector('#taskproject').querySelectorAll('option');
function giveSelection(appId)
{
var appSelector = document.querySelector('#taskapp');
var projectSelector = document.querySelector('#taskproject');
projectSelector.innerHTML = '';
if(projectSelector != null)
{
for(var i=0; i<projectsList.length; i++)
{
if(projectsList[i].id.split('_')[1] === appId)
{
projectSelector.appendChild(projectsList[i]);
}
}
}
}
<select id="taskapp" name="new_app_id" onchange="giveSelection(this.value)">
<option value="55" >Proj1</option>
<option value="33" >Proj2</option>
<option value="62" >Proj3</option>
<option value="69" >Proj4</option>
</select>
<select id="taskproject" name="new_project_id">
<option id="appWithProject_55" value="239" >Proj1 - a</option>
<option id="appWithProject_55" value="273" >Proj1 - b</option>
<option id="appWithProject_55" value="289" >Proj1 - c</option>
<option id="appWithProject_33" value="106" >Proj2 - a</option>
<option id="appWithProject_33" value="105" >Proj2 - b</option>
<option id="appWithProject_62" value="263" >Proj3 - a</option>
<option id="appWithProject_62" value="264" >Proj3 - b</option>
<option id="appWithProject_69" value="285" >Proj4 - a</option>
<option id="appWithProject_69" value="286" >Proj4 - b</option>
</select>
Here, if I choose Proj2 on first select, it will show me only Proj2 - a and Proj2 - b on the second select (on chrome). On IE11, it will show me 2 "options" with no text inside.

The problem is that IE has a very strange behavior when you set innerHTML. It removes the text nodes of the elements it's removing. This is non-standard, and arguably a bug. (In fact, I seem to recall reporting it as a bug at one point.)
You can work around it by not using innerHTML = '' to clear the select, but instead using removeChild:
var projectsList = document.querySelector('#taskproject').querySelectorAll('option');
function giveSelection(appId)
{
var appSelector = document.querySelector('#taskapp');
var projectSelector = document.querySelector('#taskproject');
if(projectSelector != null)
{
// Not this: projectSelector.innerHTML = '';
while (projectSelector.firstChild) {
projectSelector.removeChild(projectSelector.firstChild);
}
for(var i=0; i<projectsList.length; i++)
{
if(projectsList[i].id.split('_')[1] === appId)
{
projectSelector.appendChild(projectsList[i]);
}
}
}
}
<select id="taskapp" name="new_app_id" onchange="giveSelection(this.value)">
<option value="55" >Proj1</option>
<option value="33" >Proj2</option>
<option value="62" >Proj3</option>
<option value="69" >Proj4</option>
</select>
<select id="taskproject" name="new_project_id">
<option id="appWithProject_55" value="239" >Proj1 - a</option>
<option id="appWithProject_55" value="273" >Proj1 - b</option>
<option id="appWithProject_55" value="289" >Proj1 - c</option>
<option id="appWithProject_33" value="106" >Proj2 - a</option>
<option id="appWithProject_33" value="105" >Proj2 - b</option>
<option id="appWithProject_62" value="263" >Proj3 - a</option>
<option id="appWithProject_62" value="264" >Proj3 - b</option>
<option id="appWithProject_69" value="285" >Proj4 - a</option>
<option id="appWithProject_69" value="286" >Proj4 - b</option>
</select>
Side note: You also had the innerHTML thing before the if (projectSelector != null) check. I've put it inside that if's body instead.

Related

Displaying multiple Select Values into an alert? [duplicate]

This question already has answers here:
How to get all selected values of a multiple select box?
(28 answers)
Closed 5 years ago.
I'm still a beginner hence this is difficult, but how do I display the options I selected into an alert box. So it would be "You selected (value), (value), (value)".
This is my select list
<form id='form1'>
<select id="options" multiple >
<option value="action">Action</option>
<option value="animation">Animation</option>
<option value="children">Children</option>
<option value="classics">Classics</option>
<option value="comedy">Comedy</option>
<option value="documentary">Documentary</option>
<option value="drama">Drama</option>
<option value="family">Family</option>
<option value="foreign">Foreign</option>
<option value="games">Games</option>
<option value="horror">Horror</option>
<option value="music">Music</option>
<option value="new">New</option>
<option value="scifi">Sci-Fi</option>
<option value="sports">Sports</option>
<option value="travel">Travel</option>
</select>
</form>
Should I add a button. But what I'm struggling with is the javascript.
The easiest way to access selected elements of a select tag is with the "selectedOptions" property.
I would do it this way:
var form = document.getElementById('form1');
form.addEventListener('submit', function () {
var select = form.querySelector('#options'),
options = select.selectedOptions,
values = [];
for (var i = options.length - 1; i >= 0; i--) {
values.push(options[i].value);
}
alert('You selected: ' + values.join(', '));
}, false);
Try something like this:
function selectedValues()
{
var x=document.getElementById("options");
var selectedValues= '';
for (var i = 0; i < x.options.length; i++) {
if(x.options[i].selected ==true){
selectedValues += x.options[i].value + ", ";
}
}
alert("You selected: "+ selectedValues.slice(0, -2));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form id='form1'>
<select id="options" multiple onchange="selectedValues()">
<option value="action">Action</option>
<option value="animation">Animation</option>
<option value="children">Children</option>
<option value="classics">Classics</option>
<option value="comedy">Comedy</option>
<option value="documentary">Documentary</option>
<option value="drama">Drama</option>
<option value="family">Family</option>
<option value="foreign">Foreign</option>
<option value="games">Games</option>
<option value="horror">Horror</option>
<option value="music">Music</option>
<option value="new">New</option>
<option value="scifi">Sci-Fi</option>
<option value="sports">Sports</option>
<option value="travel">Travel</option>
</select>
</form>

Jquery disallow same value from multiple select lists

I need to make sure that when a value is selected in one of the lists, it cannot be selected in any of the others. Can this be done with jQuery, or do I need to create a validator that does not allow selection of the same value?
I have multiple select lists which are basically numbers only, i.e.
<select id="101_1">
<option value="0">0</option>
<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="50"> 50</option>
</select>
<select id="101_2">
<option value="0">0</option>
<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="50"> 50</option>
</select>
<select id="101_1">
<option value="0">0</option>
<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="50"> 50</option>
</select>
I have gotten the following code to work for one of my colleagues :
HTML :
<h3>List 1</h3>
<select id="select1">
<option value="null">-- select --</option>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
</select>
<h3>List 2</h3>
<select id="select2">
<option value="null">-- select --</option>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
</select>
<h3>List 3</h3>
<select id="select3">
<option value="null">-- select --</option>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
</select>
JS with jQuery :
$(document).ready(function() {
var selectState = {
'select1': 'null',
'select2': 'null',
'select3': 'null'
};
$('select').change(function() {
var selectId = $(this).attr('id');
var selectedOptionValue = $(this).val();
// for each other select element
$('select[id!="' + selectId + '"]').each(function(index) {
// enable the old option
$(this).find('option[value="' + selectState[selectId] + '"]').removeAttr('disabled');
if (selectedOptionValue !== 'null') { // if selected a real option
// disable the new option
$(this).find('option[value="' + selectedOptionValue + '"]').attr('disabled', 'disabled');
}
});
selectState[selectId] = selectedOptionValue; // update the new state at the end
});
});
And here is a CodePen
I opted to hide the option tag instead of remove as I suggested. Here is a complete working html file. I was going to post it on jsfiddle, but for some reason it wouldn't work. Be very aware of copy/paste errors in the .change handlers. Spent some time myself wondering why it wasn't working, but it was a copy/paste error.
Note that this code only works if every select tag has the same options. But, it works dynamically if you add or remove options later, while keeping them in sync as noted.
If you need it to work with lists with only some of the same options, you will be stuck dealing with having IDs on the options and then working the hiding/unhiding based on that instead of indexing into the children, but the basic mechanics are the same.
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
<style type="text/css">
.gone {display: none;}
</style>
<script type="text/javascript">
$(document).ready(function() {
// hides the option selected in the others
var hideValue = function(oldval, val, options, others) {
var unhideChild = -1;
var hideChild = -1;
// find which child to hide in the others
// also find the value we change from and unhide it
for (var i=1; i<options.length; i++) {
var optval = $(options[i]).val();
console.log(optval);
if (optval == val) {
hideChild = i;
}
if (optval == oldval) {
unhideChild = i;
}
}
if (unhideChild == -1 && oldval != "None") {
console.log("uh oh");
return;
}
if (hideChild == -1 && val != "None") {
console.log("uh oh");
return;
}
// hide them using the passed in selectors
for (var j=0; j<others.length; j++) {
if (oldval != "None") {
console.log("unhiding: " + others[j] + " v: " + unhideChild);
$($(others[j]).children()[unhideChild]).removeClass("gone");
}
if (val != "None") {
console.log("hiding: " + others[j] + " v: " + hideChild);
$($(others[j]).children()[hideChild]).addClass("gone");
}
}
}
// we need to keep track of the old values so we can unhide them if deselected
var val1 = "None";
var val2 = "None";
var val3 = "None"
$('#101_1').change(function() {
var opts = $('#101_1').children();
var v = $('#101_1').val();
hideValue(val1, v, opts, ["#101_2", "#101_3"]);
val1 = v;
});
$('#101_2').change(function() {
var opts = $('#101_2').children();
var v = $('#101_2').val();
hideValue(val2, v, opts, ["#101_1", "#101_3"]);
val2 = v;
});
$('#101_3').change(function() {
var opts = $('#101_3').children();
var v = $('#101_3').val();
hideValue(val3, v, opts, ["#101_2", "#101_1"]);
val3 = v;
});
});
</script>
</head>
<body>
<select value="None" id="101_1">
<option value="None">None</option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<select value="None" id="101_2">
<option value="None">None</option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<select value="None" id="101_3">
<option value="None">None</option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</body>
</html>
Also, if you need the "None" value to not be there, remove it. Then just start the select ta 101_1 having 0 selected, 101_2 with 1 selected etc. Then make sure to trigger the change handler. Also, without the None option, the for loop needs to start with i=0.
So basically add this to the end of the script and make sure var i starts at 0 instead of 1.
$('#101_1').val('0');
$('#101_2').val('1');
$('#101_3').val('2');
$('#101_1').trigger('change');
$('#101_2').trigger('change');
$('#101_3').trigger('change');

How to filter / clone select box options with jQuery?

I have the following two select boxes:
<select id="project">
<option data-person_ids="[75,76,77]">None</option>
<option data-person_ids="[77]">Project A</option>
<option data-person_ids="[75,76]">Project B</option>
<option data-person_ids="[75]">Project C</option>
</select>
<select id="person">
<option value="75">Person A</option>
<option value="76">Person B</option>
<option value="77">Person C</option>
</select>
How can I filter the #person options based on the value selected in #project?
This is a jQuery code snippet that a colleague came up with but I was unable to get it working because I am still new to jQuery:
$(function() {
var $person = $('#person');
$allPersonOptions = $person.children();
$('#project').on('change', function() {
var selected_project = $('#project').data('person_ids');
filterOptions($allPersonOptions.clone(), +selected_project).appendTo($person.empty());
});
});
function filterOptions($options, id) {
return $options.filter(function() {
return $.inArray(id, $(this).data('project_ids')) > -1
});
}
Thanks for any help in this matter.
Well your colleague gave you bad code.
First
var selected_project = $('#project').data('person_ids');
will return undefined since it is not on the select, it is on the option. It does not magically get the selected option's data attribute
var selected_project = $('#project option:selected').data('person_ids');
Next there is a random + in the code
filterOptions($allPersonOptions.clone(), +selected_project).appendTo($person.empty());
^^^
That is going to do a conversion, bad.
Next the filter code is looking for a data attribute
return $.inArray(id, $(this).data('project_ids')) > -1
There is no data attribute on that select's options. And the arguments are switched.
$(function() {
var $person = $('#person');
$allPersonOptions = $person.children();
$('#project').on('change', function() {
var selected_project = $('#project option:selected').data('person_ids');
filterOptions($allPersonOptions.clone(), selected_project).appendTo($person.empty());
});
});
function filterOptions($options, id) {
return $options.filter(function() {
return $.inArray(parseInt(this.value,10), id) > -1
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="project">
<option data-person_ids="[75,76,77]">None</option>
<option data-person_ids="[77]">Project A</option>
<option data-person_ids="[75,76]">Project B</option>
<option data-person_ids="[75]">Project C</option>
</select>
<select id="person">
<option value="75">Person A</option>
<option value="76">Person B</option>
<option value="77">Person C</option>
</select>
I have a version that reuses allPersonOptions (no need to clone) and only copies applicable options.
$(function() {
var $person = $('#person');
$allPersonOptions = $person.children();
$('#project').on('change', function() {
var ids = $('#project option:selected').data('person_ids');
$person.empty();
$allPersonOptions.each( function() {
var id = parseInt($(this).attr('value'));
if ($.inArray(id, ids) != -1 )
$person.append(this);
})
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="project">
<option data-person_ids="[75,76,77]">None</option>
<option data-person_ids="[77]">Project A</option>
<option data-person_ids="[75,76]">Project B</option>
<option data-person_ids="[75]">Project C</option>
</select>
<select id="person">
<option value="75">Person A</option>
<option value="76">Person B</option>
<option value="77">Person C</option>
</select>

Hide/show the selected option on a secondary select

I have two <select> elements with different IDs.
When the user selects a value from the first select box, I want the second select box to only display connected values.
My code:
<select id="ExtraField_1" name="ExtraField_1">
<option value="1">test1</option>
<option value="2">test2</option>
<option value="3">test3</option>
<option value="4">test4</option>
<option value="5">test5</option>
<option value="6">test6</option>
<option value="7">test7</option>
<option value="8">test8</option>
<option value="9">test9</option>
<option value="10">test10</option>
<option value="11">test11</option>
<option value="12">test12</option>
</select>
<select id="ExtraField_2" name="ExtraField_2">
<option value="1">test1</option>
<option value="2">test2</option>
<option value="3">test3</option>
<option value="4">test4</option>
<option value="5">test5</option>
<option value="6">test6</option>
<option value="7">test7</option>
<option value="8">test8</option>
<option value="9">test9</option>
<option value="10">test10</option>
<option value="11">test11</option>
<option value="12">test12</option>
<option value="13">test13</option>
<option value="14">test14</option>
<option value="15">test15</option>
<option value="16">test16</option>
<option value="17">test17</option>
<option value="18">test18</option>
<option value="19">test19</option>
<option value="20">test20</option>
</select>
So when user selects "test1" from first select boxm he will see only "test2", "test3" and "test4" on the second select box; "test2" from first will show "test6", "test7" and "test8" in the second box.
How can I use JavaScript to resolve this problem?
If you can use jQuery then you can always just clear and append the options to the second select.
$('#ExtraField_1').change(function(){
$('#ExtraField_2').find('option').remove()
if($(this).val() == '1'){
$('#ExtraField_2').append($("<option </option>").attr('value','2').text('test2'));
$('#ExtraField_2').append($("<option></option>").attr('value','3').text('test3'));
$('#ExtraField_2').append($("<option></option>").attr('value','4').text('test4'));
}
if($(this).val() == '2'){
$('#ExtraField_2').append($("<option></option>").attr('value','5').text('test5'));
$('#ExtraField_2').append($("<option></option>").attr('value','6').text('test6'));
$('#ExtraField_2').append($("<option></option>").attr('value','7').text('test7'));
}
});
​
http://jsfiddle.net/8XVuv/2/
using only javascript is a bit more complicated but I would still take the same approach.
function createOption(otext,oValue){
var newOption = document.createElement('option');
newOption.text = otext;
newOption.value = oValue;
return newOption;
}
function clearSelect(theSelect){
for(var i = 0;i <= theSelect.options.length+1;i++)
{
theSelect.remove();
}
}
function onSelect(theSelect){
var nextSelect = document.getElementById('ExtraField_2');
clearSelect(nextSelect);
var selected = theSelect.options[theSelect.selectedIndex];
if(selected.value == 1){
nextSelect.add(createOption('test2','2'));
nextSelect.add(createOption('test3','3'));
nextSelect.add(createOption('test4','4'));
}
if(selected.value == 2){
nextSelect.add(createOption('test5','5'));
nextSelect.add(createOption('test6','6'));
nextSelect.add(createOption('test7','7'));
}
}
with html:
<select id="ExtraField_1" name="ExtraField_1" onchange="javascript: onSelect(this);" >
<option value="0">Select a test..</option>
<option value="1">test1</option>
<option value="2">test2</option>
<option value="3">test3</option>
<option value="4">test4</option>
<option value="5">test5</option>
<option value="6">test6</option>
<option value="7">test7</option>
<option value="8">test8</option>
<option value="9">test9</option>
<option value="10">test10</option>
<option value="11">test11</option>
<option value="12">test12</option>
</select>
<select id="ExtraField_2" name="ExtraField_2">
<option value="0">Select from the left</option>
</select>​
as you can see it still does what you expect but you are not hiding options.
http://jsfiddle.net/upKzW/13/
$('#ExtraField_1').change(function() {
$('#ExtraField_2').val(this.value);
});
http://jsfiddle.net/judearasu/rF8G6/

How to automatically set the size of a drop-down list?

I'm trying to write a script in Greasemonkey that will automatically set the size of Drop-down lists (there can be more than one...) on the number of selection options, but with my limited JavaScript knowledge I don't really know how to do this.
Example of subject:
<select name="z_pos_id">
<option value="2463">Option A</option>
<option value="2609">Option B</option>
<option value="3013">Option C</option>
</select>
<select name="z_pos_id">
<option value="140">Option AA</option>
<option value="3038">Option AB</option>
<option value="3519">Option AC</option>
<option value="2645">Option AD</option>
</select>
Example of desired Output:
<select size="3" name="z_pos_id">
<option value="2463">Option A</option>
<option value="2609">Option B</option>
<option value="3013">Option C</option>
</select>
<select size="4" name="z_pos_id">
<option value="140">Option AA</option>
<option value="3038">Option AB</option>
<option value="3519">Option AC</option>
<option value="2645">Option AD</option>
</select>
So, <select name="z_pos_id">should be replace with this:
<select size="*the number of options*" name="z_pos_id">
Thank you all for the help!
Here's a complete script. It should be fairly self explanatory:
// ==UserScript==
// #name _Auto-size select selects.
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #grant none
// ==/UserScript==
var posIdSelects = document.querySelectorAll ("select[name=z_pos_id]");
for (var J = posIdSelects.length - 1; J >= 0; --J) {
var numOpts = posIdSelects[J].getElementsByTagName ("option").length;
posIdSelects[J].setAttribute ("size", numOpts);
}
$(document).ready(function() {
var ln = $("select[name=z_pos_id] option").length ;
alert(ln); // you can delete this alert after your test
$("select[name=z_pos_id]").attr('size', ln);
});

Categories