In javascript, I'm generating this HTML element:
tdSecond.innerHTML += `<select id="train_input" class="custom-select" style="width: 70px; margin-bottom: 10px;" onchange="setAndReload(${data[i]['id']})">
So on a change of this select, I want to call setAndReload function with data[i]['id'] parameter. However, when I do a console log of that parameter in my setAndReload function, what I get is this:
[object HTMLHeadingElement]
How can I pass that parameter into onclick correctly, so that I get the real string?
data[i] is an object, that holds id attribute (and that's string). I want to have a string sent as a parameter.
When you try to get the selected value in onchange function as parameter you can do something like this:
function myFunction(selectedObject) {
var x = document.getElementById("mySelect").value;
document.getElementById("demo").innerHTML = `You selected: ${selectedObject.value} House`;
}
<!DOCTYPE html>
<html>
<body>
<p>Select a new house from the list.</p>
<select id="mySelect" onchange="myFunction(this)">
<option value="Tiny">Tiny House</option>
<option value="Big">Big House</option>
<option value="Small">Small House</option>
</select>
<p>When you select a new house, a function is triggered which outputs the value of the selected house.</p>
<p id="demo"></p>
</body>
</html>
The above example gets you the selected value on OnChange event.
Have a nice day!
You really should use data attributes and delegation
document.getElementById("myTable").addEventListener("change",function(e) {
const tgt = e.target;
if (tgt.classList.contains("custom-select")) {
setAndReload(tgt.dataset.id,tgt.value)
}
})
using
tdSecond.innerHTML += `<select id="train_input" class="custom-select"
style="width: 70px; margin-bottom: 10px;" data-id ="${data[i]['id']}")>`
I am sure you could use a map on the data array instead of concatenating to innerHTML
You might want to use a single event listener instead of multiple inline event handlers, as shown in the following snippet. I wasn't sure exctly what your select element (including its change listener) is intended to do, so I just made it show/hide the corresponding Train from the data array.
You can also sometimes avoid headaches (such as more complicated maintenance, and errors resulting from typos) by creating DOM elements in JavaScript and appending them to existing elements, rather than trying to parse complex strings for use by the innerHTML method -- so the addTrainInput function demonstrates this. (Compare the "sloppier" code I included that displays each train in the setAndReload listener.)
See the in-code comments for further clarification.
// Identifies some DOM elements, and gets the data array
const
trSecond = document.getElementById("trSecond"),
output = document.getElementById("output"),
data = getData();
// Dynamically adds select elements, and shows trains
for(let i = 0; i < data.length; i++){
addTrainInput(data[i]["id"]); // Adds each select element
}
setAndReload(); // To show all trains right away
// Calls setAndReload whenever something in trSecond changes
trSecond.addEventListener("change", setAndReload);
// Defines the change listener (which also gets called directly)
function setAndReload(event){
// B/c we're listening on parent div, checks event's actual target before proceeding
if(event && !event.target.classList.contains("custom-select")){
return;
}
output.innerHTML = ""; // Hides all trains for now
for(let trainInput of trSecond.children){ // Loops through select elements
if(trainInput.value == "shown"){
// Finds matching train in data
const train = data.find(obj => obj.id == trainInput.dataset.id);
// Shows the train
output.innerHTML += train.image + "<br><br>";
}
}
}
// Defines a function to add each select elemement
// (The corresponding train is tracked via a `data-id` attribute)
function addTrainInput(trainId){
// Makes the select element (with class and data-id attrubutes)
trainInput = document.createElement("select");
trainInput.classList.add("custom-select");
trainInput.dataset.id = trainId;
// Makes an option and appends it to the select
opt1 = document.createElement("option");
opt1.value = "shown";
opt1.textContent = trainId + " Shown";
trainInput.appendChild(opt1);
// Makes another option and appends it to the select
opt2 = document.createElement("option");
opt2.value = "hidden";
opt2.textContent = trainId + " Hidden";
trainInput.appendChild(opt2);
// Finally, adds the select (with its options) to the DOM
trSecond.appendChild(trainInput);
}
// Just returns our initial data array
function getData(){
const data = [
{id: "Train1", image: "  < picture of Train 1 >"},
{id: "Train2", image: "  < picture of Train 2 >"},
{id: "Train3", image: "  < picture of Train 3 >"},
];
return data;
}
.custom-select { width: 110px; margin-right: 10px; }
#output { margin-top: 25px; font-size: 1.2em; }
<div id=trSecond></div>
<div id="output"></div>
Related
I'm fairly new to Javascript, and am trying to make my first program.
The program essentially presents users with a series of dropdown boxes, and their selections will all be collated at the end to form a joined text string. My original JSFiddle shows the program working correctly for one dropdown box, and I'm now trying to rework it into a function so that this process can be repeated for several different dropdown boxes.
My NEW JSFiddle shows that I've now re-written my code as a function, and accept the two parameters (categoryOptions - the different arrays to populate the selection boxes with) and (selector - the actual selection in the HTML doc to target).
// Step 4 - Function which will print the selected value into the content HTML element
// Need helping turning this into a callback for the function above.
// I want this function to run but only when the select box is changed.
function printSelection() {
var finalSelection = selector.value;
console.log(document.getElementById("content").innerHTML = finalSelection);
}
}
populateSelects (progressOptions, progressSelector);
I now want to print the value selected by the user to the page and assign it to 'finalSelection'. Unfortunately it says 'Uncaught ReferenceError: selector is not defined"' but I'm not sure how to pass it the value that they have selected.
I understand I need to do this as a callback, that takes place 'on change' but am not sure how to do this with the main populateSelects function.
Any help is appreciated!
You can create a function and on onchange of select you can call the function passing this as an argument.
this points to the html element calling the function.
You can try below snippet. Also I have modified populateSelects a bit to be able to create all dropdowns in single call.
// Step 1 - Store Strings to be passed to categoryOptions Parameter
let progressOptions = ["Just testing!", "XX has made excellent progress", "XX has made good progress", "XX has made poor progress"];
// Behaviour Options
let behaviourOptions = ["XX has excellent behaviour", "XX has good behaviour", "XX has poor behaviour"];
// Attendance Options
let attendanceOptions = ["XX has excellent attendance", "XX has good attendance", "XX has poor attendance"];
// Punctuality Options
let punctualityOptions = ["XX has excellent punctuality", "XX has good punctuality", "XX has poor punctuality"];
// Improvement Options
let improvementsOptions = ["XX should carry on as they have", "XX could make some improvements", "XX must improve"];
// Step 2 - Target the ID; objects to be used in the select below.
let dropDownConfig = [{
id: "progressDropdown",
categoryOptions: progressOptions
},
{
id: "behaviourDropdown",
categoryOptions: behaviourOptions
},
{
id: "attendanceDropdown",
categoryOptions: attendanceOptions
},
{
id: "punctualityDropdown",
categoryOptions: punctualityOptions
},
{
id: "improvementsDropdown",
categoryOptions: improvementsOptions
},
]
// Step 3 - For Loop Passing the Values from progressOptions as option elements in HTML
function populateSelects(dropDownConfig) {
for (let di = 0; di < dropDownConfig.length; di++) {
for (let i = 0; i < dropDownConfig[di].categoryOptions.length; i++) {
let opt = dropDownConfig[di].categoryOptions[i];
let el = document.createElement("option");
el.text = opt;
el.value = opt;
document.getElementById(dropDownConfig[di].id).add(el);
}
}
}
// Step 4 - Function which will print the selected value into the content HTML element
// Need helping turning this into a callback for the function above.
// I want this function to run but only when the select box is changed.
function printSelection(e) {
document.getElementById("content").innerHTML+= e.value+' ';
}
populateSelects(dropDownConfig);
<body>
<select id="progressDropdown" onchange="printSelection(this)">
<option>Progress Dropdown</option>
</select>
<select id="behaviourDropdown" onchange="printSelection(this)">
<option>Behaviour Dropdown</option>
</select>
<select id="attendanceDropdown" onchange="printSelection(this)">
<option>Attendance Dropdown</option>
</select>
<select id="punctualityDropdown" onchange="printSelection(this)">
<option>Punctuality Dropdown</option>
</select>
<select id="improvementsDropdown" onchange="printSelection(this)">
<option>Improvements Dropdown</option>
</select>
<div id="content"></div>
</body>
You can create a function in which you can pass the dropdown element and extract its value.
function printSelected(element){
document.getElementById("content").innerHTML = element.value;
}
And change your HTML as :
<select id="progressDropdown" onchange="printSelected(this)">
<option>Progress Dropdown</option>
</select>
You can use this function with all other dropdowns.
I made a drop down list using the <select> and <option> tag, where every time a new input is typed, the program creates a new option tag with value attribute to add it to the existing options in the drop down list.
However, my client uses a MacOS and he wanted to move the check mark on the drop down list to the recently added option. The check mark only moves when you click on the selected line, but in my case, I want it to also move to the recently added/typed data.
Here is the HTML code:
<!-- Created select tag so user can access history of talk -->
<div style="top:60px;position:absolute;z-index:2" id="speechBox">
<!-- The select tag acts like a drop down button, so it passes its value to the input box and not to itself -->
<select id = 'combo-box' title = "Saved Talk" onchange="document.getElementById('userText').value=this.options[this.selectedIndex].text; document.getElementById('idValue').value=this.options[this.selectedIndex].value;">
</select>
<span class = "dropdown" name = "Saved Talk"></span>
<input id ="userText" name="userText" type="text" onfocus="this.select()" ></input>
<input name="idValue" id="idValue" type="hidden">
<button id="speakText" class="toolbutton" title="Speak"></button>
<hr>
</div>
And the JS:
hiddenArray(); // Access speakArray
// Function containing the speakArray, which saves the recent talk array
function hiddenArray() {
speakArray = [];
}
function playVoice(language, text) {
playing = text;
//Adds option when text is spoken
var addUserInput = document.createElement("OPTION");
addUserInput.setAttribute("value", playing);
addUserInput.text = playing;
document.getElementById("combo-box").appendChild(addUserInput);
speakArray.push(playing); // Adds recent talks to speakArray
if(document.getElementById('mode').innerHTML=="2"){
//After the voice is loaded, playSound callback is called
getBotReply(text);
setTimeout(function(){
loadVoice(language, playSound);
}, 4000);
}
else{
loadVoice(language, playSound);
}
}
I've figured it out in the end. Here is the code:
hiddenArray(); // Access speakArray
// Function containing the speakArray, which saves the recent talk array
function hiddenArray() {
speakArray = [];
}
function playVoice(language, text) {
playing = text;
//Adds option when text is spoken
var addUserInput = document.createElement("OPTION");
addUserInput.setAttribute("value", playing);
addUserInput.text = playing;
document.getElementById("combo-box").appendChild(addUserInput);
document.getElementById("combo-box").value = playing;
speakArray.push(playing); // Adds recent talks to speakArray
if(document.getElementById('mode').innerHTML=="2"){
//After the voice is loaded, playSound callback is called
getBotReply(text);
setTimeout(function(){
loadVoice(language, playSound);
}, 4000);
}
else{
loadVoice(language, playSound);
}
}
So what I did here is asign the value of the combo box (select tag) to the recently added option (variable playing).
I created a div and a button. when the button clicked, there will be a group of element(included 1 select box and 2 text inputs) inserted into the div. User can add as many group as they can, when they finished type in data of all the group they added, he can hit save button, which will take the value from each group one by one into the JSON object array. But I am stuck in the part how to get the value from each group, so please help, thank you.
The code for the div and the add group button function -- AddExtra() are listed below:
<div id="roomextra">
</div>
function AddExtra() {
$('#roomextra').append('<div class=extra>' +
'<select id="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" id="insetLength">' +
'Width(m): <input type="text" id="insetWidth">' +
'Height(m): <input type="text" id="insetHeight">' +
'</div>');
}
function GetInsetOffSetArray (callBack) {
var roomIFSDetail = [{
"IsInset": '' ,
"Length": '' ,
"Width": '' ,
"Height": ''
}];
//should get all the value from each group element and write into the array.
callBack(roomIFSDetail);
}
This should just about do it. However, if you're dynamically creating these groups, you'll need to use something other than id. You may want to add a class to them or a data-* attribute. I used a class, in this case. Add those classes to your controls so we know which is which.
var roomIFSDetail = [];
var obj;
// grab all of the divs (groups) and look for my controls in them
$(.extra).each(function(){
// create object out of select and inputs values
// the 'this' in the selector is the context. It basically says to use the object
// from the .each loop to search in.
obj = {
IsInset: $('.isInset', this).find(':selected').val() ,
Length: $('.insetLength', this).val() ,
Width: $('.insetWidth', this).val() ,
Height: $('.insetHeight', this).val()
};
// add object to array of objects
roomIFSDetail.push(obj);
});
you'd better not to use id attribute to identity the select and input, name attribute instead. for example
$('#roomextra').append('<div class=extra>' +
'<select name="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" name="insetLength">' +
'Width(m): <input type="text" name="insetWidth">' +
'Height(m): <input type="text" name="insetHeight">' +
'</div>');
}
and then, usr foreach to iterate
$(".extra").each(function() {
var $this = $(this);
var isInset = $this.find("select[name='isInset']").val();
var insetLength = $this.find("input[name='insetLength']").val();
// ... and go on
});
A common problem. A couple things:
You can't use IDs in the section you're going to be repeating, because IDs in the DOM are supposed to be unique.
I prefer to use markup where I'm writing a lot of it, and modify it in code rather than generate it there.
http://jsfiddle.net/b9chris/PZ8sf/
HTML:
<div id=form>
... non-repeating elements go here...
<div id=roomextra>
<div class=extra>
<select name=isInset>
<option>Inset</option>
<option>OffSet</option>
</select>
Length(m): <input id=insetLength>
Width(m): <input id=insetWidth>
Height(m): <input id=insetHeight>
</div>
</div>
</div>
JS:
(function() {
// Get the template
var container = $('#roomextra');
var T = $('div.extra', container);
$('#addGroup').click(function() {
container.append(T.clone());
});
$('#submit').click(function() {
var d = {};
// Fill d with data from the rest of the form
d.groups = $.map($('div.extra', container), function(tag) {
var g = {};
$.each(['isInset', 'insetLength', 'insetWidth', 'insetHeight'], function(i, name) {
g[name] = $('[name=' + name + ']', tag).val();
});
return g;
});
// Inspect the data to ensure it's what you wanted
debugger;
});
})();
So the template that keeps repeating is written in plain old HTML rather than a bunch of JS strings appended to each other. Using name attributes instead of ids keeps with the way these elements typically work without violating any DOM constraints.
You might notice I didn't quote my attributes, took the value attributes out of the options, and took the type attributes out of the inputs, to keep the code a bit DRYer. HTML5 specs don't require quoting your attributes, the option tag's value is whatever the text is if you don't specify a value attribute explicitly, and input tags default to type=text if none is specified, all of which adds up to a quicker read and slimmer HTML.
Use $(".extra").each(function() {
//Pull info out of ctrls here
});
That will iterate through all of your extra divs and allow you to add all values to an array.
I am creating a test form. I have created a form with a list of steps to test.
Instead of every item on the list needing:
<input type="radio" name="step1">Pass<input type="radio" name="step1">Fail
I wanted to create a function so I could just call it every time to create it.
This is my function so far:
function createPassFail(name)
{
var Pass = document.createElement('input');
Pass.type = "radio";
Pass.name = name;
document.getElementById("Pass").innerHTML = "Pass";
var Fail = document.createElement('input');
Fail.type = "radio";
Fail.name = name;
document.getElementById("Fail").innerHTML = "Fail";
}
And then I call it with:
<li>Step One: Turn the TV On
<input id = "step1" onload="createPassFail(this.value)">
</li>
All this does is create a textbox which is not what I was going for. I am also not sure if onload is correct.
Instead of passing in the value to the function you should pass the id:
onload="createPassFail(this.id)"
// ^^
I say your event should be onblur because I don't think onload is the event handler you should be using. You can use my suggestion or maybe set up a button next to the text box which, when clicked (using onclick) does what you want.
Moreover, you haven't inserted the pass or fail elements into HTML. Try this:
document.body.appendChild(Pass);
document.body.appendChild(Fail);
This inserts the newly-created elements directly to the end of the body element. If you would like them to be child to some element therein, you would have to access the element with a suitable method. For example, with getElementById:
document.getElementById( element ).appendChild(Pass); // do the same for Fail
However, this can all be easily done with jQuery.
$(document).ready(function() {
function createPassFail(name)
{
$('body').append('<input type="radio" id="' + name + '">Pass');
$('body').append('<input type="radio" id="' + name + '">Fail');
}
$('#step1').ready(function() {
createPassFail(this.id);
});
});
Live Demo
I've been tasked with building a very simple app that that has a series of dropdowns in rows of 2, when 2 are selected, a simple functions concatenates the 2 values and gives an output next to them like so:
dropdown1 dropdown2 Output
What I'm trying to get is, once the second dropdown value is chosen the function runs and displays the output where it says output. But currently, what seems to happens is the output is displayed in a new window.
Here's what I have so far (HTML):
<form>
<select id="test">
<option>Arena/Quantum Barcelona LTBC</option>
<option>Arena/Quantum Spain LTES</option>
</select>
<select id="name" onchange="tryThis()">
<option>Name</option>
<option>Name1</option>
</select>
</form>
JavaScript:
function tryThis() {
var string, string1 = '';
var e = document.getElementById("test");
string = e.options[e.selectedIndex].text;
var a = document.getElementById("name");
string1 = a.options[a.selectedIndex].text;
document.write(string+'_'+string1);
}
Am I making this more difficult than it needs to be?!
That's because document.write clears the page before displaying something. You should never need to use that function.
Instead, you could append it to e.g. the body:
document.body.appendChild(
document.createTextNode(string + '_' + string2)
);
Have you noticed that your JS function is called tryThis() and on the event handler you're calling tryThsis()
However in your case I'd refrain from using document.write, good alternatives are appending to the body or having a DIV and changing the innerHTML of that DIV
First put an id on your form so that it is easier to access.
var a = (function () {
var myForm = document.getElementById("myForm"),
magic = function () {
var a = myForm.getElementsByTagName("select"),
b,
c = [];
for (b = a.length - 1; b > -1; b -= 1) {
c.push(a[b].value);
}
alert(c.join(" ") + " output");
};
myForm.onclick = magic;
}());
You were not specific as to what the extra "output" is supposed to be or how you want the data returned, but here you go. Instead of using an alert you could push the result into the value of a different form element. Do not use document.write as this cannot be deferred. If you attempt to defer a document.write operation it will replace the entirety of the body contents of the current page.