I'm trying to change the innerHTML of a element based on the value of the previous element.
I have the javascript correctly grabbing the current value and everything works correctly in Firefox, Safari, Chrome and Opera. IE is a pain.
sample code:
<form action="soap.php" method="post">
<select name="circuitproduct" id="circuitproduct" onchange="bandwidthfunction();">
<option>Dedicated Voice</option>
<option>Frame Relay</option>
<option>ATM</option>
<option>Dedicated Internet</option>
<option>IP Solutions Private Port</option>
<option>IP Solutions Enhanced Port</option>
<option>Private Line – Domestic</option>
<option>Int’l Private Line</option>
<option>Qwest Metro Private Line (QMPL)</option>
<option>Qwest Metro Ethernet Private Line (QMEPL)</option>
</select><br />
<select name="term" id="term">
<option value="1-Year">1-Year</option>
<option value="2-Year">2-Year</option>
<option value="3-Year">3-Year</option>
</select>
<select id="bandwidth">
</select>
<select id="sublooptype">
</select>
</form>
sample javascript:
function bandwidthfunction() {
var product = document.getElementById('circuitproduct').value;
if (product == 'Dedicated Voice') {
document.getElementById('bandwidth').innerHTML = ('<option value="DS-1">DS-1</option><option value="DS-3">DS-3</option><option value="OC-3">OC-3</option><option value="OC-12">OC-12</option>');
document.getElementById('sublooptype').innerHTML = ('<option value="Special Access">Special Access</option><option>CO MtPt - Special Access</option><option>CPA Special Access</option>');
}
else if (product == 'Frame Relay') {
document.getElementById('bandwidth').innerHTML = ('<option value="DS-1">DS-1</option><option value="DS-3">DS-3</option><option value="OC-3">OC-3</option><option value="OC-12">OC-12</option>');
document.getElementById('sublooptype').innerHTML = ('<option value="Special Access">Special Access</option><option>CO MtPt - Special Access</option><option>CPA Special Access</option>');
}
Well, first of all you have a closing tag for the select that you try to put inside the select element, which makes the code invalid.
Then there might be a problem with how the select element treats it's content. When the HTML code is parsed, the select element doesn't have any child elements, like a regular element does. Instead the options are items in it's options collection.
If you want to change the items in the select element, change the content of it's option collection. I.e. to add items, create option objects using the document.createElement method and add to the collection. Example:
var opt = document.createElement('OPTION');
opt.text = 'Choose me';
opt.value = 42;
document.getElementById('bandwidth').options.add(opt);
You have to remove the "select"-Element and the end of setting the innerHTML-Property. This is not a part of innerHTML. Its the end-tag of the element 'bandwith' itself.
document.getElementById('bandwidth').innerHTML = ('<option value="DS-1">DS-1</option><option value="DS-3">DS-3</option><option value="OC-3">OC-3</option><option value="OC-12">OC-12</option>');
Here's a handy hack I came across that works in both FF and IE as a workaround to the inability to change innerHTML on select elements.
document.getElementById('bandwidth').outerHTML = document.getElementById('bandwidth').outerHTML.replace( document.getElementById('bandwidth').innerHTML + '</select>' , '<option value="DS-1">DS-1</option><option value="DS-3">DS-3</option><option value="OC-3">OC-3</option><option value="OC-12">OC-12</option>' + '</select>' );
or as a function for readability:
function swapInnerHTML(objID,newHTML) {
var el=document.getElementById(objID);
el.outerHTML=el.outerHTML.replace(el.innerHTML+'</select>',newHTML+'</select>');
}
I recently came across this problem with IE. I came up with a turnkey solution that works with the following things in mind:
You don't want to use jQuery
Need it to work in IE < 9
You want to append ( not replace the existing options ) string options into an existing select element
The select must be a type of "select-one"
Must wrap selects in their own parent element
We have many landing pages requesting the same information (age, products, country, state etc... ) but with different select options. The implementation I use appends new select options. This was done to allow a custom default option per lading page. One page may have the first option as "select item" another may have "choose one" and so forth.
Select format:
<div> <!-- you MUST wrap the select in a tag without any siblings -->
<select name="age" id="form-age">
<option value="">Choose Age</option>
</select>
</div> <!-- you MUST wrap the select in a tag without any siblings -->
Here is the function to APPEND/ADD values:
function addOptions(el, options){
// checks to make sure element exists and is a select
if(el && el.type === "select-one"){
el.innerHTML = el.innerHTML + options;
el.parentNode.innerHTML = el.outerHTML; // needed for IE
}
}
Now to execute the function pass in the select object and string values:
addOptions(
document.getElementById("form-age"),
'<option value="1">18-25</option><option value="2">26-35</option><option value="3">36-45</option><option value="4">46-55</option><option value="5">56-65</option><option value="6">66-75</option><option value="7">76-85</option><option value="8">86+</option>'
);
This will generate a select with the options passed, even in IE!
<div> <!-- you MUST wrap the select in a tag without any siblings -->
<select name="age" id="form-age">
<option value="">Choose Age</option>
<option value="1">18-25</option><option value="2">26-35</option><option value="3">36-45</option><option value="4">46-55</option><option value="5">56-65</option><option value="6">66-75</option><option value="7">76-85</option><option value="8">86+</option>
</select>
</div> <!-- you MUST wrap the select in a tag without any siblings -->
If you needed the script to REPLACE the values use the following:
function replaceOptions(el, options){
if(el && el.type === "select-one"){
el.innerHTML = options;
el.parentNode.innerHTML = el.outerHTML; // needed for IE
}
}
I hope this helps someone else!
A quick search shows this has been a known bug in IE since at least IE5. You could try to use createElement and make options and append to the select object, or use a library like jQuery and append the html to the node (which must take care of the magic necessary to work in IE).
The real cause of the problem is that due to a DOM parsing/updating problem, IE will not insert child option elements into a select element. Even IE9 still has this problem (later versions not checked).
You have to put the select in a div or span and replace the whole select. Below you will find an example that shows that then IE will play ball as well. Because this innerHTML problem generally occurs when dynamically generating selects, I made an AJAX & PHP example.
The html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chain(ed) select with AJAX and PHP</title>
<style>
select {
min-width: 170px;
}
option.toSelect {
background: yellow;
}
</style>
</head>
<body>
<form action="whatever.php">
<span>
<select id="cities" onchange="getOptions(this.value,'airlinesContainer')">
<option value="">Select a city:</option>
<option value="boston_airlines">Boston</option>
<option value="chicago_airlines" class="toSelect">Chicago</option>
<option value="newyork_airlines">New York</option>
</select>
</span>
<span id="airlinesContainer">
<select>
</select>
</span>
<span id="classesContainer">
<select>
</select>
</span>
</form>
<script>
function getOptions(qValue,containerId) {
var ajaxRequest = new XMLHttpRequest();
if ((qValue == "") || (containerId == "")) {
alert('Invalid selection.');
return;
}
ajaxRequest.onreadystatechange = function() {
if ((ajaxRequest.readyState == 4) && (ajaxRequest.status == 200)) {
document.getElementById(containerId).innerHTML = ajaxRequest.responseText;
}
}
ajaxRequest.open("GET","getoptions.php?q="+qValue,true);
ajaxRequest.send();
}
</script>
</body>
</html>
.
And the php file, which should be named 'getoptions.php' and should be put in the same folder:
<?php
$q = $_GET['q'];
$chicago_airlines ='
<select id="airlines" onchange="getOptions(this.value,\'classesContainer\')">
<option value="">Select an airline:</option>
<option value="delta_classes">Delta</option>
<option value="klm_classes" class="toSelect">KLM</option>
<option value="united_classes">United Airlines</option>
</select>';
$klm_classes ='
<select id="classes">
<option value="business">World Business Class</option>
<option value="comfort">Economy Comfort</option>
<option value="economy">Economy</option>
</select>';
if ($q == 'chicago_airlines') {
echo $chicago_airlines;
}
elseif ($q == 'klm_classes') {
echo $klm_classes;
}
else {
echo '<select>
<option>Invalid selection</option>
</select>';
}
?>
.
Be sure to select only the options with a yellow background, in this demo.
use Jquery
$('#bandwidth').html('<option value="DS-1">DS-1</option><option value="DS-3">DS-3</option><option value="OC-3">OC-3</option><option value="OC-12">OC-12</option>');
Related
I am trying to populate a form option value if it's attribute quantity equals zero.
My goal is to add the a message to the current option value
My html is:
<select class="valid">
<option disabled="disabled" selected="selected" value="">Select Bar</option>
<option value="1" quantity="99">value 1 </option>
<option value="2" quantity="0">value 2 </option>
</select>
So far I've tried the following in jQuery but it's not working:
if($(this).attr('quantity') == '0') {
$(this).append('<span>message</span>');
}
If you don't care about preserving the original message, than you can simply say $(this).text("message"). Leave out the <span> since it cannot be rendered inside of an <option> element anyway.
if($(this).attr('quantity') == '0') {
$(this).text('message');
}
If you want to preserve the original message, you have a couple options. One would simply be to append the new message to the original, however, it may get tricky to remove it later, so I would suggest having some sort of delimiter so you can easily identify the original vs the appended message, like so:
var $option = $(this);
if($option.attr('quantity') == '0') {
$option.text($option.text().trim() + ' (message)');
}
Then, to remove the message, you can do something like this:
$option.text($option.text().slice(0, $option.text().indexOf('(')).trim());
You can populate the option with like this,
$(document).ready(function () {
$('.valid').on('change', function () {
if ($(this.options[this.selectedIndex]).attr('quantity') == 0) {
$(this.options[this.selectedIndex]).find('span').remove();
$(this.options[this.selectedIndex]).append('<span>Message</span>')
}
});
});
JSFIDDLE
I'm not entirely sure of what you're trying to achieve from your question, but you cannot add html elements to an option element. You can however change the text as follows:
$(document).on('change', '.valid', function(){
var selected = $('.valid > option:selected');
if(selected.attr('quantity') == '0'){
selected.text('something else');
}
});
if you wanted to append an error you could do so by using jQuery append() or concatenating with the original value. Alternatively if you wanted it as validation outside of the select box, you could simply assign to the value of a div by replacing the line inside of the if statement.
<select class="valid" onchange="quality(this.options[this.selectedIndex].getAttribute('quantity'));">
<option disabled="disabled" selected="selected" value="">Select Bar</option>
<option value="1" quantity="99">value 1 </option>
<option value="2" quantity="0">value 2 </option>
</select>
<span id="msg"></span>
<script type="text/javascript">
function quality(val) {
if(parseInt(val) == 0){
document.getElementById("msg").innerHTML = "Message";
}
}
echo "<select name = error_type id='error_type$rowIndex' name='error_type$rowIndex' class='error_type'>
<option value= >Select Type</option>
<option value=Category1>Category1</option>
<option value=Category2>Category2</option>
</select>
</td><td>
<select disabled=disabled id='remarks$rowIndex' name='remarks$rowIndex' class='remarks'>
<option value= >Select Subtype </option>
<option rel='Category1' value='Subcategory1.1'>Subcategory1.1</option>
<option rel='Category1' value='Subcategory1.2'>Subcategory1.2</option>
<option rel='Category1' value='Subcategory1.3'>Subcategory1.3</option>
<option rel='Category2' value='Subcategory2.1'>Subcategory2.1</option>
<option rel='Category2' value='Subcategory2.2'>Subcategory2.2</option>
<option rel='Category2' value='Subcategory2.3'>Subcategory2.3</option>
</select>";
I have a php table which outputs 'n' number of rows,each row with 2 dropdowns. The above section of code works only for the first row of the Php table, but when the next row is changed, the first row's subcategory also changes.How do i make individual rows act independently.
the js is,
$(function(){
var $error_type = $(".error_type"),
$remarks = $(".remarks");
$error_type.on("change",function(){
var _rel = $(this).val();
$remarks.find("option").attr("style","");
$remarks.val("");
if(!_rel) return $remarks.prop("disabled",true);
$remarks.find("[rel="+_rel+"]").show();
$remarks.prop("disabled",false);
});
});
The cs is,
.remarks option{
display:none;
}
.remarks option.label{
display:block;
}
--EDIT--
$(function(){
var $error_type = $(".error_type"),
$remarks = $(".remarks");
$error_type.on("change",function(){
var $remarks = $(this).closest("tr").find(".remarks");
var _rel = $(this).val();
$remarks.find("option").attr("style","");
$remarks.val("");
if(!_rel) return $remarks.prop("disabled",true);
$remarks.find("[rel="+_rel+"]").show();
$remarks.prop("disabled",false);
});
});
This is going to resolve to all matching elements:
$remarks = $(".remarks");
You're doing that once when the page loads and then always operating on all of those elements. Instead, remove that line completely and find the specific element you're looking for when the event happens, using the source of the event as a starting point.
Perhaps something like this:
$error_type.on("change", function(){
var $remarks = $(this).closest("tr").find(".remarks");
// the rest of your handler code
});
The idea is that when the change event happens, you start from this (which is the element that triggered the event), traverse the DOM to a common parent element (given your HTML that's likely a <tr>), then finds the specific target .remarks element(s) contained specifically within that parent.
I have two select boxes like so:
<select id="one">
<option value="default">Select File</option>
<option value="path/to/file1">File One</option>
<option value="path/to/file2">File Two</option>
<option value="path/to/file3">File Three</option>
</select>
<select id="two">
<option value="default">Select File</option>
<option value="path/to/file4">File Four</option>
<option value="path/to/file5">File Five</option>
<option value="path/to/file6">File Six</option>
</select>
<p class="button_image">
<a onclick="download(document.getElementById("one").value)"></a>
</p>
Here is my download function:
function download(file) {
if (file == 'default') return;
window.location = 'http://www.mysite.com/download/' + file;
}
This works fine for one select box, but I can't seem to figure out how to use the same button image. Oh yah, the p.class=button_image has background image that is a button with hover effects.
The reason I want these select boxes to be separate is because they each represent a group of files, eg, 32-bit versus 64-bit. So they cannot be combined, because it won't flow with the page design.
I've tried some if/else blocks in PHP using the getElementById but I'm getting stuck. This is what I tried and it seems to only partially work:
<?php
if ('document.getElementById(\"one\")' == 'one') {
echo "<a onclick='download(document.getElementById(\"one\").value)'></a>";
}
else if ('document.getElementById(\"two\")' == 'two') {
echo "<a onclick='download(document.getElementById(\"one\").value)'></a>";
}
?>
I should note that I don't necessarily need to use PHP in this case to solve this problem. It was just an option I tried because I'm using PHP for the server-side programming. I could be happy with any number of options, so long as they work.
Thanks.
** EDIT **
This design might be flawed. But the intention is that either a file from box one is downloaded OR a file from box two is downloaded. If one selection is made, then the other should be rest to default and vice versa. This is what I'm working on now.
** EDIT **
I ended up goign with Dawson Loudon's answer for one part and I created another function based on Barmar's comment that looks like this:
// resets other select box when selected
function reset_index(id) {
document.getElementById(id).selectedIndex = 'default';
}
An A element as a button doesn't seem appropriate, just use an img.
Anyhow, a function to use the first select with a selected option other than the first can be something like:
function getPath() {
var select;
var args = arguments;
for (var i=0, iLen=args.length; i<iLen; i++) {
select = document.getElementById(arg[i]);
if (select && select.selectedIndex > 0) {
window.location = 'http://www.mysite.com/download/' + select.value;
}
}
}
The above expects the first option to be the default selected, so if it's selected, or no option at all is selected, the select's selectedIndex will be 0 or -1 respsectively. I would ensure one option is selected by adding the selected attribute to the first one:
<option value="default" selected>Select File</option>
and the call is:
<img src="buttonImage.jpg" onclick="download('one', 'two');">
though you might want to add a class to the select elements and get them using getElementsByClassName or similar and loop over that collection, rather than hard code the ids.
Try replacing this:
<p class="button_image">
<a onclick="download(document.getElementById('one').value)"></a>
</p>
with:
<p class="button_image">
<a onclick="download(document.getElementById('one').value, document.getElementById('two').value)"></a>
</p>
and then replace your download function with this:
function download(file1,file2) {
if (file1 == 'default' && file2 == 'default'){
return;
}
else if(file1 != 'default'){
window.location = 'http://www.mysite.com/download/' + file1;
}
else{
window.location = 'http://www.mysite.com/download/' + file2;
}
}
I want to create 2 multiselect side by side. The first one is populated, but the 2nd is empty. The 2nd gets populated only when I select an option from the 1st one and depends on the value of the 1st one.
I'm thinking the only way to do this is with javascript. Can someone confirm this, and do you know of existing examples.
I'm using jquery, but prefer to not use plugins.
I'm also thinking to use Zend so if an existing component exists that would be great.
Here's a demo
You can easily do this with some DOM manipulation.
HTML
<select id="from" multiple>
<option value="-">King</option>
<option value="9">Queen</option>
<option value="5">Rook</option>
<option value="3">Knight</option>
<option value="3">Bishop</option>
<option value="1">pawn</option>
</select>
<select id="to" multiple>
</select>
javascript
var from = document.getElementById("from");
var to = document.getElementById("to");
from.onchange = function(){
//remove this to allow for duplicates
to.innerHTML = "";
var fromOptions = from.getElementsByTagName("option");
for(var i in fromOptions) {
if (fromOptions[i].selected == true) {
//remove "cloneNode(true)" to simultaniusly
//remove the node from the from list.
to.appendChild(fromOptions[i].cloneNode(true));
}
}
}
I have a relatively simple form which asks a variety of questions. One of those questions is answered via a Select Box. What I would like to do is if the person selects a particular option, they are prompted for more information.
With the help of a few online tutorials, I've managed to get the Javascript to display a hidden div just fine. My problem is I can't seem to localise the event to the Option tag, only the Select tag which is no use really.
At the moment the code looks like (code simplified to aid clarity!):
<select id="transfer_reason" name="transfer_reason onChange="javascript:showDiv('otherdetail');">
<option value="x">Reason 1</option>
<option value="y">Reason 2</option>
<option value="other">Other Reason</option>
</select>
<div id="otherdetail" style="display: none;">More Detail Here Please</div>
What I would like is if they choose "Other Reason" it then displays the div. Not sure how I achieve this if onChange can't be used with the Option tag!
Any assistance much appreciated :)
Note: Complete beginner when it comes to Javascript, I apologise if this is stupidly simple to achieve!
Setup the onchange event handler for the select box to look at the currently selected index. If the selected index is that of the 'Other Reason' option, then display the message; otherwise, hide the division.
<html>
<head>
<script type="text/javascript">
window.onload = function() {
var eSelect = document.getElementById('transfer_reason');
var optOtherReason = document.getElementById('otherdetail');
eSelect.onchange = function() {
if(eSelect.selectedIndex === 2) {
optOtherReason.style.display = 'block';
} else {
optOtherReason.style.display = 'none';
}
}
}
</script>
</head>
<body>
<select id="transfer_reason" name="transfer_reason">
<option value="x">Reason 1</option>
<option value="y">Reason 2</option>
<option value="other">Other Reason</option>
</select>
<div id="otherdetail" style="display: none;">More Detail Here Please</div>
</body>
</html>
Personally, I'd take it a step further and move the JavaScript into an external file and just include it in the header of the page; however, for all intents and purposes, this should help answer your question.
After reading Tom's great response, I realised that if I ever added other options to my form it would break. In my example this is quite likely, because the options can be added/deleted using a php admin panel.
I did a little reading and altered it ever so slightly so that rather than using selectedIndex it uses value instead.
<script type="text/javascript">
window.onload = function() {
var eSelect = document.getElementById('transfer_reason');
var optOtherReason = document.getElementById('otherdetail');
eSelect.onchange = function() {
if(eSelect.value === "Other") {
optOtherReason.style.display = 'block';
} else {
optOtherReason.style.display = 'none';
}
}
}
</script>
Hope this helps someone else in the future!
Tom's answer is elegant, and neatly puts the JS away from the HTML markup. As mentioned, it could be even moved to an external file. However it adds quite much "nonsense" to the code, like multiple anonymous function assignments etc.
If you want quick solution, you can put it all in the onchange() inside the select tag as well. Pick the one you see more fit.
<select id="transfer_reason" name="transfer_reason" onchange="document.getElementById('otherdetail').style.display = (this.selectedIndex === 2) ? 'block' : 'none';">
<option value="x">Reason 1</option>
<option value="y">Reason 2</option>
<option value="other">Other Reason</option>
</select>
<div id="otherdetail" style="display: none;">More Detail Here Please</div>