I'm trying to use a input number type to update how many times a particular amount of content is added to the page. In the example I'm doing it with a p tag but in my main model I'm using it on a larger scale with multiple divs. However, I can't seem to be able to get this to work. If someone can see where I'm going wrong that would be very helpful.
function updatePage() {
var i = document.getElementById("numerInput").value;
document.getElementById("content").innerHTML =
while (i > 1) {
"<p>Content<p/><br>";
i--;
};
}
<input type="number" value="1" id="numberInput">
<br>
<input type="button" value="Update" onclick="updatePage()">
<div id="content">
<p>Content
<p>
<br>
</div>
First, you have quite a few problems that need addressing:
You are setting the .innerHTML to a while loop, which is invalid because a loop doesn't have a return value. And, inside your loop, you just have a string of HTML. It isn't being returned or assigned to anything, so nothing will happen with it.
You've also mis-spelled the id of your input:
document.getElementById("numerInput")
Also, don't use inline HTML event attributes (i.e. onclick) as there are many reasons not to use this 20+ year old antiquated technique that just will not die. Separate all your JavaScript work from your HTML.
Lastly, your HTML is invalid:
"<p>Content<p/><br>"
Should be:
"<p>Content</p>"
Notice that in addition to fixing the syntax for the closing p, the <br> has been removed. Don't use <br> simply to add spacing to a document - do that with CSS. <br> should be used only to insert a line feed into some content because that content should be broken up, but not into new sections.
Now, to solve your overall issue, what you should do is set the .innerHTML to the return value from a function or, more simply just the end result of what the loop creates as I'm showing below.
// Get DOM references just once in JavaScript
let input = document.getElementById("numberInput");
let btn = document.querySelector("input[type='button']");
// Set up event handlers in JavaScript, not HTML with standards-based code:
btn.addEventListener("click", updatePage);
function updatePage() {
var output = ""; // Will hold result
// Instead of a while loop, just a for loop that counts to the value entered into the input
for (var i = 0; i < input.value; i++) {
// Don't modify the DOM more than necessary (especially in a loop) for performance reasons
// Just build up a string with the desired output
output += "<p>Content</p>"; // Concatenate more data
};
// After the string has been built, update the DOM
document.getElementById("content").innerHTML = output;
}
<input type="number" value="1" id="numberInput">
<br>
<input type="button" value="Update">
<div id="content">
<p>Content</p>
</div>
And, if you truly do want the same string repeated the number of times that is entered into the input, then this can be a lot simpler with string.repeat().
// Get DOM references just once in JavaScript
let input = document.getElementById("numberInput");
let btn = document.querySelector("input[type='button']");
// Set up event handlers in JavaScript, not HTML with standards-based code:
btn.addEventListener("click", updatePage);
function updatePage() {
// Just use string.repeat()
document.getElementById("content").innerHTML = "<p>Content</p>".repeat(input.value);
}
<input type="number" value="1" id="numberInput">
<br>
<input type="button" value="Update">
<div id="content">
<p>Content</p>
</div>
As #ScottMarcus pointed out you had the following issues:
While Loops do not need a ; at the end of while(args) {}
Your .innerHTML code was in the wrong place
You had a typo in getElementById("numerInput") which I changed to getElementById("numberInput")
Code
function updatePage() {
// Get input value
var numberInput = document.getElementById("numberInput").value;
// Will be used to store all <p> contents
var template = "";
while (numberInput > 0) {
// Add all contents into template
template += "<p>Content<p/><br>";
numberInput--;
}
// Append upon clicking
document.getElementById("content").innerHTML = template;
}
<input type="number" value="1" id="numberInput">
<br>
<input type="button" value="Update" onclick="updatePage()">
<div id="content">
</div>
Related
This question already has answers here:
Stop input from clearing on innerHTML insert
(4 answers)
Closed 8 months ago.
Hi Folks I'm new to JS World.
I am trying to add A <div> dynamically to my HTML with the help of JavaScript.
var counter = 0;
function add_more_animals() {
counter+=1;
html = `<div id="animal${counter}">
<input type="text" name="animalName${counter}">
<input type="text" name="animalType${counter}">
</div>`;
var form = document.getElementById("animals");
form.innerHTML+=html;
}
<div id="animals">
<div id="animal0">
<input type="text" name="animalName0">
<input type="text" name="animalType0">
</div>
</div>
<button type="button" onclick="add_more_animals()">Add animals (+)</button>
The issue I'm facing:
While I populate the fields of animalName0 and animalType0 on UI. After I click on add button so as to insert more animals data, new div is created as per JS logic written in file. But my earlier inputs to animalName0 & animalType0 becomes empty & I have to insert data there all over again.
Can you please help here?
The problem stems from the line form.innerHTML+=html which is shorthand for form.innerHTML = form.innerHTML + html. When it gets the form.innerHTML it is grabbing the HTML only; The text typed into the inputs are not a part of this HTML. When the innerHTML gets set, think form.innerHTML = form.innerHTML + html, brand new HTML elements are created based off of the HTML only, and any state, including typed in text, is lost. Any event listeners will also be lost in this process.
The proper way of adding a new element while leaving adjacent elements in place is to create the new element with document.createElement, and add it with a function like .appendChild, like so
var counter = 0
function add_more_animals() {
counter+=1;
// Create an empty element
const newEl = document.createElement('div')
newEl.id = `catalogue${counter}`
// Add the first input
const nameInput = document.createElement('input')
nameInput.name = `animalName${counter}`
newEl.appendChild(nameInput)
// Now the second one
const typeInput = document.createElement('input')
typeInput.name = `animalType${counter}`
newEl.appendChild(typeInput)
// And finally attach everything to the animals form
document.getElementById("animals").appendChild(newEl)
}
<div id="animals">
<div id="animal0">
<input type="text" name="animalName0">
<input type="text" name="animalType0">
</div>
</div>
<button type="button" onclick="add_more_animals()">Add animals (+)</button>
As you can imagine, this can become verbose if you have a large amount of HTML to add. To make this process easier they came out with template tags which you may prefer using. Use them either like this or like this.
I have created a simple calculator that takes variable #1 and variable #2 and multiplies them to generate a result.
When I change variable #1 the result instantly changes. However, when I change variable #2 the result remains unchanged.
How do I reconfigure my code so that the result instantly changes when either variable is altered?
HTML:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h6>Variable #1</h6>
<input id="var1">
<h6>Variable #2</h6>
<input id="var2">
<h6>Result</h6>
<input readonly="readonly" id="result">
<script>
$(document).ready(function(){
var mt=$("#var1");
mt.keyup(function(){
var total=isNaN(parseInt(mt.val()* $("#var2").val())) ? 0 :(mt.val()* $("#result").val())
$("#result").val(total);
});
});
</script>
You have many things going wrong here,
you need to bind keyup event in var1 textbox and var2 textbox both
Also, your multiply formula is also wrong. Here is the desire code:
$(document).ready(function(){
var mt=$("#var1,#var2");
mt.keyup(function(){
debugger;
var total= 0;
if(!isNaN(parseInt($("#var1").val())* parseInt(parseInt($("#var2").val())))){
total= parseInt($("#var1").val())* parseInt(parseInt($("#var2").val()));
}
$("#result").val(total);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h6>Variable #1</h6>
<input id="var1">
<h6>Variable #2</h6>
<input id="var2">
<h6>Result</h6>
<input readonly="readonly" id="result">
Consider binding keyup events on both #var1 and #var2 inputs using the following jQuery syntax #var1, #var2 to achieve this desired behaviour, as shown:
$(document).ready(function(){
// Select and bind keyup event to both "var" input elements using
// this syntax
$('#var1, #var2')
.keyup(function(){
// Adjust your keyup handler to perform calculation when keyup
// occurs on either input field
var total= 0;
if(!isNaN(parseInt($("#var1").val())* parseInt($("#var2").val()))){
total = parseFloat($("#var1").val())* parseFloat($("#var2").val());
}
$("#result").val(total);
});
});
I just want to answer in vanilla Javascript for future reference of the problem..
I make var1,var2 class="input", then querySelect them both, then loop them, so that when you put any number to them, their value(product) will be produce in the id="result"
if you did not put any number to them, the default value is zero(0) for both of them, so let say, you only put 10 to var1, then the output will only be 10, and if you put non numeric character, then the output is NaN.
let input = document.querySelectorAll(".input");
let var1 = document.querySelector("#var1");
let var2 = document.querySelector("#var2");
let output = document.querySelector("#result");
function result(var1=0,var2=0) {
output.value = Number(var1)*Number(var2);
}
for(let i=0;i<input.length;i++)
{
input[i].addEventListener(`keyup`,()=>result(var1.value,var2.value))
}
<h6>Variable #1</h6>
<input id="var1" class="input">
<h6>Variable #2</h6>
<input id="var2" class="input">
<h6>Result</h6>
<input readonly="readonly" id="result">
By the way you can also make the code much shorter by instead of putting the id var1,var2 value, you can instead just put the input class[0], and [1] it's the same..
so it can also be done this way.
let input = document.querySelectorAll(".input");
let output = document.querySelector("#result");
function result(var1=0,var2=0) {
output.value = Number(var1)*Number(var2);
}
for(let i=0;i<input.length;i++)
{
input[i].addEventListener(`keyup`,()=>result(input[0].value,input[1].value))
}
<h6>Variable #1</h6>
<input id="var1" class="input">
<h6>Variable #2</h6>
<input id="var2" class="input">
<h6>Result</h6>
<input readonly="readonly" id="result">
By the way if you want to follow the same logic by using ternary operator,
let's follow his example, by using ternary operator,
change the result function to this.
function result(var1=0,var2=0) {
(var1*var2 ===0)? output.value=0: output.value=Number(var1) * Number(var2);
}
I have a HTML-JavaScript script in which the user can insert data to a new array [] by using a form's text field and an insert button.
By pressing insert button, the user inserts the data typed into the array.
I have a function which prints all the values of the array into <p id="demo"></p> and runs itself every 100 milliseconds in order to be updated with the arrays values.
I also have a reset button to delete every array's value when clicked.
What I want to do is add a delete button next to each array's value in order to be easier for the user to delete the wrong value he inserted.
I am using this code to insert values and print them:
HTML:
<div align="center">
<form id="form1">
<input type="text" name="fname" id="fname" placeholder="Type here!">
</form>
<br>
<input type="button" id="Button Insert" onclick="myFunction()" value="Insert">
<input type="button" onclick="myFunction3()" value="Reset">
</div>
<p id="demo" align="center"></p>
JavaScript/JQuery:
var all_values =[];
function myFunction() {
var temp_val = $("#fname").val();
all_values.push(temp_val);
document.getElementById("form1").reset();
}
setInterval(function () {
$("#demo").html(all_values.join("<br>"));
}, 100);
function myFunction3() {
all_values.length = 0;
}
To be more specific I want something like these things: iOS example JSFiddle Example 1 JSFiddle Example 2.
Could you please help me? Thanks in advance.
I'd do it the other way around.
Remove setInterval as it's really bad way to do such things.
Remove white spaces from the id attribute (id="Button-Insert", not id="Button Insert")
Don't use onclick attributes. Instead, register click event handlers with jQuery
// caching is a good practice when you reffer to the same elements multiple times:
var all_values =[], demo = $("#demo"), form = $("#form1")[0], fname = $("#fname");
$('#Button-insert').click(function(){
var temp_val = fname.val();
all_values.push(temp_val);
// create delete button along with the value
demo.append('<p>'+temp_val+' <button value="'+temp_val+'" type="button" class="del-btn">Delete</button></p>');
form.reset();
});
$('#Button-reset').click(function(){
all_values = [];
demo.html('');
});
// event delegation for dynamic elements:
demo.on('click', '.del-btn', function(){
all_values.splice(all_values.indexOf($(this).val()), 1);
$(this).parent().remove();
});
JSFiddle
Simply create the delete buttons at the same time you create the table.
function loadvalues(){
var i, button;
$('#demo').empty();
for(i in all_values){
$('#demo').append(all_values[i]);
button = $('<button>',{'text':'Delete'}).click(function(){
all_values.splice(this,1);
loadvalues();
}.bind(i)).appendTo('#demo');
$('#demo').append('<br>');
}
}
Also you don't need to poll, you could simply add each one on demand with a function like this:
function addVal(){
var val = $("#fname").val(), i = all_values.length;
all_values.push(val);
$('#demo').append(val);
button = $('<button>',{'text':'Delete'}).click(function(){
all_values.splice(this,1);
loadvalues();
}.bind(i)).appendTo('#demo');
$('#demo').append('<br>');
}
I had some typos, the code works,
Check here:
http://codepen.io/anon/pen/QbvgpW
I have a bunch of div's that have the same functionality and I'm trying to write a function for them.
Basically they have a predetermined value and a user input value and those need to be multiplied.
I've looked through a bunch of other questions and this is the closest one I could find. Almost exactly, but none of those answers work.
Any help would be great. Thanks in advance!
<div>
<label>enter value for multiple here</label>
<input type="text" class="multiple" factor="foo1"/>
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
<label>enter value for multiple here</label>
<input type="text" class="multiple" factor="foo2"/>
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
</div>
Here's the JS:
$('.mulitplyBtn').click(function() {
var factor = $(this).closest('attr.factor').val();
var multiple = $(this)closest('.multiple').val();
answer = (factor * multiple);
};
This would work:
$('.multiplyBtn').click(function() { // you had multiplyBtn spelled wrong here
var cur = $('.multiplyBtn').index($(this)); // get index of clicked btn
var factor = $('.multiple').eq(cur).data('factor'); // get factor from matching input
var multiple = $('.multiple').eq(cur).val(); // get value from matching input
answer = (Number(factor) * Number(multiple)); // make sure both are numbers then multiply
alert(answer);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<label>enter value for multiple here</label>
<input type="text" class="multiple" data-factor="4" />
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
<br>
<label>enter value for multiple here</label>
<input type="text" class="multiple" data-factor="7" />
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
</div>
In the first line you used " and ' try using the same quotes (I mean using ".multiplyBtn" or '.multiplyBtn' )
Second time, 3rd line you didn't use any quote when calling .multiple. So turn it in that format : var multiple = $(this)closest('.multiple').val()
let me know the result
You have at least two typos and are using the wrong jQuery function.
Typos:
$('.mulitplyBtn') should be $('.mulitplyBtn')
$(this)closest should be $(this).closest
Wrong function:
closest() searches the parents, and the only parent here is the DIV with no class. What you probably want is to use parent() to go up to the DIV, then find() to search the parent's children for a specific element:
$(this).parent().find('.multiple').val()
attr.factor does not work like this.
try it like this:
$('.multiplyBtn').click(function() {
var container = $(this).prev('.multiple'); //don't forget the "dot"
var multiple = container.val();
var factor = container.attr('factor'); //since it is the same container.
var answer = (factor * multiple); //what exactly are you tryin to multiply?
};
I'd like to be able to find the number value of the courseAmount input field upon submit, and then generate new input fields (into the hourForm form underneath the initialForm) through the onsubmit method in javascript, and then retrieve the value from each of the generated input fields upon the submission of the hourForm form and place those values into an array.
However, I'm having difficulty with actually generating the input fields with javascript, and I suspect that I'm having difficulty with retrieving the value of the courseAmount input and porting that to my createInput() function, but I'm not exactly sure if that's the issue.
Here's my HTML:
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<form id="initialForm" method="post" onsubmit="createInput()" action="">
<label>Number of hours for which you would like to study</label>
<input type="number" name="overallHours" id="overallHours" class="stored" min="1" max="20" step="1" value="1"/>
<label>Number of courses you would like to study for</label>
<input type="number" name="courseAmount" id="courseAmount" class="stored" min="1" max="20" step="1" value="1"/>
<input type="submit" class="submitStudy" value="Submit"/>
</form>
<form id="hourForm" method="post" onsubmit="calcHours">
<label>State the desired time spent working in each course</label>
</form>
</body>
And here's my Javascript:
var notedOverallHours = document.getElementById("overallHours").value * 60;
var courseNumberTotal = document.getElementById("courseAmount").value;
var counter = 0;
function createInput() {
var newForm = document.getElementById("hourForm");
document.getElementById("initialForm").style.display = "none";
document.getElementById("hourForm").style.display = "block";
for (i = 0; i <= courseNumberTotal; i++) {
newForm.innerHTML = "<label>Course #" + (counter + 1) + "</label>" + "<input type='number' name='courseHours' class='newInputs' min='1' max='9' step='1' value='1'/>";
counter++;
}
newForm.innerHTML = "<input type='submit' value='submit'/>";
}
Can someone help me figure this Javascript out? My JSFiddle attempts have been futile because JSFiddle does not take kindly to forms reloading the page.
Thank you!
From the mdn page about innerHTML: "Removes all of element's children, parses the content string and assigns the resulting nodes as children of the element." https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML
Generally speaking you do not want to use innerHTML at all. There is almost always a better approach. In this case this will be createElement and appendChild.
Furthermore, there is no such thing as "onsubmit" method. What you are calling like that is an HTML attribute which registers a handler for the submit event. http://www.quirksmode.org/js/introevents.html
However using html attributes has its serious drawbacks: http://www.quirksmode.org/js/events_advanced.html
Considering all that, here is what I would do: http://jsfiddle.net/ashnur/rwod4z1d/
HTML:
<form id="initialForm" method="post" action="">
<label>Number of hours for which you would like to study</label>
<input type="number" name="overallHours" id="overallHours" class="stored" min="1" max="20" step="1" value="1" /><hr>
<label>Number of courses you would like to study for</label>
<input type="number" name="courseAmount" id="courseAmount" class="stored" min="1" max="20" step="1" value="1" /><hr>
<input type="submit" class="submitStudy" value="Submit" />
</form>
<form id="hourForm" method="post" >
<label>State the desired time spent working in each course</label><hr>
</form>
js:
var notedOverallHours = document.getElementById("overallHours").value * 60;
var courseNumberTotal = document.getElementById("courseAmount").value;
var counter = 0;
var initialForm = document.getElementById("initialForm");
var hourForm = document.getElementById("hourForm");
initialForm.addEventListener('submit', createInput);
hourForm.addEventListener('submit', calcHours);
function calcHours() {}
function createInput(ev) {
ev.preventDefault(); // this is not needed if you are using a bare button and the click event
var newForm = document.getElementById("hourForm");
initialForm.style.display = "none";
hourForm.style.display = "block";
for (i = 0; i <= courseNumberTotal; i++) {
addControl(newForm, "Course #" + (counter + 1));
counter++;
}
var submit = document.createElement('input');
submit.type = 'submit';
submit.value = 'submit';
newForm.appendChild(submit);
}
function addControl(form, labelText) {
var label = document.createElement('label');
var input = document.createElement('input');
var hr = document.createElement('hr');
input.type = 'number';
input.name = 'courseHours';
input.classname = 'newInputs';
input.min = '1';
input.max = '9';
input.step = '1';
input.value = '1';
label.textContent = labelText;
form.appendChild(label);
form.appendChild(input);
form.appendChild(hr);
}
As Tobias correctly pointed out, your form submission event is allowed to continue which results in a page refresh and a "reset" of all plain JavaScript data. Furthermore, you are not capturing your values (notedOverallHours and courseNumberTotal) on form submission (after the user has entered an amount), but rather when your page initializes (before the user has input anything).
So, to go about fixing this, first a tiny modification to your HTML:
...
<form id="initialForm" method="post" action="">
...
Notice that I deleted the onsubmit attribute from your form. We can capture that with an event in JavaScript itself.
Next attach an event listener to your form which prevents it from submitting and calls your createInput() function:
document.getElementById("initialForm").addEventListener('submit', function (e) {
e.preventDefault();
createInput();
});
This will attach an eventListener that listens to the submit event on your initialForm element. The first parameter is the type of event you want to listen for (submit in this case), the second is the callback you want to have fired.
The callback function always gets the event passed in (the e argument). By calling preventDefault on this event we can stop it from bubbling up and actually causing a page refresh.
Next we call the createInput() function which, after some modifications, looks like this:
function createInput() {
var notedOverallHours = document.getElementById("overallHours").value * 60;
var courseNumberTotal = document.getElementById("courseAmount").value;
var newForm = document.getElementById("hourForm");
document.getElementById("initialForm").style.display = "none";
document.getElementById("hourForm").style.display = "block";
// Add our elements
for (i = 1; i <= courseNumberTotal; i++) {
var child = document.createElement('li');
child.innerHTML = "<label>Course #" + (i) + "</label>" + "<input type='number' name='courseHours-"+ i+"' class='newInputs' min='1' max='9' step='1' value='1'/>";
newForm.appendChild(child);
}
// Add our button
var button = document.createElement('li');
button.innerHTML = "<input type='submit' value='submit'/>";
newForm.appendChild(button);
}
As you can see, I capture the notedOverallHours and courseNumberTotal variables inside the createInput() function, so they will carry whichever value was set during the form submission event.
Then we iterate over each course number. Instead of replacing the innerHTML, we first create an element (li in our case) and fill that element with a HTML string. Next we append this child element to the parent form.
Inside the loop I have removed the counter variable as you can simply use the value of i inside the loop, no need to create an extra variable. I also appended the name attribute for each child with i, so not to get any name clashes.
At the end of our function we simply create and append a new li element containing the submit button.
You can optimize this further by actually creating the label and input elements with the createElement function and set its attributes and text individually with plain JavaScript setters, instead of dumping everything inside li elements as I've done here to keeps things a bit more simple for now. I`ll leave that up as an exercise :)
I have created a rough JSFiddle with this exact code here.
When the createInput() function is called you are not having the desired results because you are reseting the newForm.innerHTML in each iteration of the loop and then again at the end. Rather than using = you should be using += to append the desired text rather than replace the existing text.
// Replacing the contents of newForm.innerHTML
newForm.innerHTML = "foo";
// Appending to newForm.innderHTML (You want to do this)
newForm.innerHTML += "foo";
Another problem is that when you press submit the page is reloading before createInput() is able to have the desired result. You most likely want to stop the page actually submitting and thus reloading when you press the submit button. To do this you can change the onsubmit attribute for the form to "return createInput()" and then add the line return false; to the end of the createInput() function to indicate to the browser that you do not wish to submit the form.