How do I use innerHTML inside a loop using JavaScript? - javascript

Here is the code and snippet:
var amount = prompt("How many list items would you like?");
if(isNaN(amount) || amount < 1) {
alert("Please enter a positive whole number");
} else {
for(i = 0; i <= amount; i++) {
document.getElementById("content").innerHTML = "Loop: " + i + "<br>";
}
}
<div id="content"></div>
Hi, I'm a new to Javascript and I can't figure this out. How can I write into the div tag "content" using the loop to display values inside the div tag per loop?

Change to += instead of = and start the for loop with 1 unless you want to print out as loop 0, loop 1 and so on...
document.getElementById("content").innerHTML += "Loop: " + i + "<br>";
var amount = prompt("How many list items would you like?");
if(isNaN(amount) || amount < 1) {
alert("Please enter a positive whole number");
} else {
for(i = 1; i <= amount; i++) {
document.getElementById("content").innerHTML += "Loop: " + i + "<br>";
}
}
<div id="content"></div>

Your code looks basically correct but you need to understand the context in which a browser executes javascript. For a given computation (event), the browser usually executes all of that computation before it does any redraws of the actual page. What this means in your case is that only the last value of innerHTML will be used. One approach to this is to accumulate the entire innerHTML value before returning (I see IsabelHM just posted that). The second would be to use something like setTimeout to spread the computation out over multiple "sessions" - something like
var i = 0;
count = function() {
document.getElementById("content").innerHTML = "Loop: " + i + "<br>";
i++;
if (i < amount) {
window.setTimeout(count, 100);
}
};
count();
Note - I haven't run that but the idea is there. I basically count at 100ms intervals.

Related

Ideas for how to catch the last index in a jscript for loop, where lengh of index is is unknown?

Consider the following for loop (and assuming we don't know 3 times table - i.e. how many results might occur).
<script summary>
function myFunction() {
var output_text = "";
var i;
for (i = 0; i < 20; i++) {
if (Number.isInteger(i/3)){
if ("e.g. this is the last index?") {"e.g.then do this?"
output_text += "This number is the last " + i ;
}else{
output_text += "The number is " + i + "<br>";
}
}
}
}
</script>
Trying to 'output_text' as something like:
The number is 0
The number is 3
The number is 6
The number is 9
The number is 12
The number is 15
The number is the last 18
Any ideas for how to catch that last loop iteration.
This is just an example as actual application is a bit wordy - but the concept is the same.
I could run a count first to get index length, but wondered if there is an easier way.
Many thanks for anyone's time. Also first go at posting - any advice welcome.
Just add 3 to the current index and check if it exceeds 19.
function myFunction() {
var output_text = "";
var i;
const max = 19;
const factor = 3;
for (i = 0; i <= max; i++) {
if (i % factor === 0){
if (i + factor > max) {
output_text += "This number is the last " + i ;
}else{
output_text += "The number is " + i + "<br>";
}
}
}
return output_text;
}
document.write(myFunction());
If you have a number divisible by 3, perform a second check to see if 20 minus i < 3 and you'll know if it's the last number.
function myFunction() {
var output_text = "";
for (var i = 0; i < 20; i++) {
if (Number.isInteger(i/3)){
if (20 - i < 3) {
output_text += "This number is the last " + i ;
}else{
output_text += "The number is " + i + "<br>";
}
}
}
document.getElementById("out").innerHTML = output_text;
}
myFunction();
<div id="out"></div>
The better approach is to show result of current iteration in the next iteration. In this case, last iteration will not be handled in the loop. So, you can handle it after easily.

Having trouble counting iterations of different outputs in my javascript code

Trying to set up code to take inputted numbers, determine whether they are negative or positive, displaying this, and then when 0 is put in the code displays the amount of positive numbers put in and the amount of negative numbers put in and then terminates. Having trouble with the counting part and I am not sure how to set this up better. I am also not sure how to set this up to terminate after 0 is put in.
function mapping() {
var num = parseInt(document.getElementById("num1").value);
var countp = 0;
var countn = 0;
if (num !== 0) {
if (num > 0) {
document.getElementById("output").innerHTML = "positive";
countp += 1;
} else {
document.getElementById("output").innerHTML = "negative";
countn += 1;
}
} else {
document.getElementById("output").innerHTML = "countp: " + countp;
document.getElementById("output").innerHTML = "countn: " + countn;
}
}
Thank you.
Two problems with the code.
1st: You need to move countp and countn outside of the function to make them global.
2nd: You are writing the positive number counts to output's html and then you are overriding it by negative count.
This should do the trick;
var countp = 0;
var countn = 0;
function mapping() {
var num = parseInt(document.getElementById("num1").value);
if (num !== 0) {
if (num > 0) {
document.getElementById("output").innerHTML = "positive";
countp += 1;
} else {
document.getElementById("output").innerHTML = "negative";
countn += 1;
}
} else {
var html = "countp: " + countp + ", countn: " + countn;
document.getElementById("output").innerHTML = html;
// this line added
countp = 0, countn = 0;
}
}
<input type="text" id="num1">
<button onclick="mapping()">Test</button>
<div id="output">
</div>
The main issue with the code is that countp and countn are local variables. Thus they are created and initialized to 0 every time the function is called. Move the two lines outside the function to fix this bug!
Another bug is the code in the last else part. There you set innerHTML twice, so the div ends up with only countn. To fix this bug, replace the last innerHTML = by innerHTML +=.
Finally, if I understand you correctly, you want that no more updates occur once 0 has been entered. To achieve this, you could add another variable like isFinal that is set to true when the user enters 0, and add a check to your function.
Some more suggestions:
Instead of if (num!==0), it is considered good practice to start with positive conditions such as if (num === 0). That way, you will also avoid some nesting in the conditions.
What happens if the user does not enter a valid number? In your code, this will be treated as negative number. Add a test for "NaN" to fix this.
You repeat the document.getElementById... many times. Use a temporary variable to fix this.
In modern JavaScript, it is recommended to use let or const instead of var.
Be consistent in your use of semicolons at the end of lines.
Thus the code ends up as:
let countp = 0;
let countn = 0;
let isFinal = false;
function mapping() {
if (isFinal) {
return;
}
const num = parseInt(document.getElementById("num1").value);
let html = "";
if (Number.isNaN(num)) {
html = "invalid";
} else if (num === 0) {
html = "countp: " + countp + "<br>";
html += "countn: " + countn;
isFinal = true;
} else if (num > 0) {
html = "positive";
countp += 1;
} else {
html = "negative";
countn += 1;
}
document.getElementById("output").innerHTML = html;
}

My Javascript prompt runs before function even if prompt is located after the function

I wrote a small practice program that shows the times table for a prompted number.
I want the table to be shown after the user is asked for which number. If the user enters a different than -1 number, I want to ask for another number.
The sequence that I'm looking for is prompt the user, show the table, prompt the user show the table ... Unfortunately the sequence in which my program works is prompt the user, prompt the user, prompt the user ... AND JUST AFTER THAT show the tables for each input.
Obviously the code is not written in that way.
// get number to show time table for
var aNumber = prompt("Enter the number for time table or -1 to stop the program", "");
while(aNumber != -1) {
timeTableFrom(aNumber); // show time table for the first number
aNumber = prompt("Enter the number for time table or -1 to stop the program", ""); // ask for another number. HERE IS THE PROBLEM - THIS LINE RUNS BEFORE THE PREVIOUS ONE!
}
document.write("stopped");
function timeTableFrom(number)
{
for (var i = 0; i <= 10; i++)
{
document.write(number + " * " + i + " = " + number*i + "<br />");
}
}
// get number to show time table for
var aNumber = null;
var div = document.getElementById("textDiv");
setTimeout(enterNumber, 0);
function enterNumber()
{
aNumber = prompt("Enter the number for time table or -1 to stop the program", "");
if (aNumber != -1) {
timeTableFrom(aNumber); // show time table for the first number
setTimeout(enterNumber, 0);
}
else
div.innerHTML += "stopped"
}
function timeTableFrom(number)
{
for (var i = 0; i <= 10; i++)
{
div.innerHTML += number + " * " + i + " = " + number*i + "<br />";
}
}
<div id="textDiv">
</div>
#Teemu is correct. And I admit, it's a bit sloppy, but this should work. Try to avoid using document.write as it can have unpredictable results. Instead try other methods of output

Why does continue; statement freeze browser?

I'm making a small script that will iterate the numbers and skip the number 5. I want to achieve this with continue; statement/label.
Here is my code:
<p id="test"></p>
<script>
var i, text;
text = "";
i = 0;
for (;i<8;) {
if (i === 5) {continue;}
text += "The number is " + i + "<br>";
i++;
}
document.getElementById('test').innerHTML = text;
</script>
I'm failing to see any typo error, but coding for more than 12 hours now, maybe I'm overseeing something obvious. If so, I apologize.
This works when I want to stop at number 5 using break; statement.
<p id="test"></p>
<script>
var i, text;
i = 0;
text = "";
for (;i<8;) {
if (i === 5) {break;}
text += "The number is " + i "<br>";
i++;
}
document.getElementById('test').innerHTML = text;
</script>
if (i === 5) {continue;}
will never allow the control to go ahead and increment the i. Thus, it'll always go back when i becomes five.
Solution:
if (i === 5) {
i++; // Increament `i` first
continue;
}
OR, using for third argument.
for (; i<8; i++) {
^^^ // Increment `i` for each iteration
One more simple thing can be done using if condition.
for (; i < 8; i++) {
// If i is not 5, then only append to the string.
if (i !== 5) {
text += "The number is " + i + "<br>";
}
}
This is causing an infinite loop as your value is never being incremented. continue will move onto the next iteration, however since you haven't defined a statement to increment your value, this never occurs.
Consider refactoring your loop as follows as opposed to performing your incrementation within the body of the loop:
<script>
var text = "";
// This is the most common approach to defining a for-loop as it handles defining
// your iterator, defining a stop condition and handles how to increment your value
// after each iteration
for (var i = 0; i < 8; i++) {
if (i === 5) {break;}
text += "The number is " + i "<br>";
}
document.getElementById('test').innerHTML = text;
</script>
if (i === 5) {continue;}
When i is 5 it never gets a chance again to reach i++. So, i will ever be 5 and you will never exit the loop.

Merging multiple columns as the table structure is written

I am trying to group multiple columns on my table by collapsing them into a single column and then use a UL list to separate the categories:
For this, what I am doing is adding a boolean to toggle the start/stop stacking, like this:
cols[0][0]="Name";
cols[0][1]=true; //<--toggler
cols[1][0]="Age";
cols[1][1]=false;
cols[2][0]="[M/F]";
cols[2][1]=false;
cols[3][0]="E-mail";
cols[3][1]=true;//<--toggler
However, using this method I have some problems:
I haven't managed to make two consecutive groups: [A][B+C][D+E][F]
the code is pretty hard to read, also to understand exactly what the toggle does
My code to write the head is the following:
document.writeln("<table><thead><tr>");
tmp = "<th>#";
flag = false;
for(i = 0; i < cols_len; i++){
if(cols[i][1]){ //if stack-toggler
if(flag){
tmp += "</th><th>-";
}
flag = !flag;
}
if(!flag){
tmp += "</th><th>" + cols[i][0];
}
}
if(flag){
tmp += "</th><th>-";
}
document.writeln(tmp + "</th></tr></thead><tbody>");
And then for the body of the table:
for(i = 0; i < 20; i++){ //some number of rows
if(i){
document.writeln("</tr>");
}
document.writeln("<tr><td>" + i + "</td>");
tmp = "";
flag = false;
for(j = 0; j < cols_len; j++){
if(cols[j][1]){ //if stack-toggler
if(flag){
document.writeln("<td><ul>" + (tmp.replace(/<td/g, "<li").replace(/td>/g, "li>")) + "</ul></td>");
tmp = "";
}
flag = !flag;
}
if(flag){
tmp += "<strong>" + cols[j][0] + ":</strong><br>";
}
tmp += "<td>...</td>";
if(!flag){
document.writeln(tmp);
tmp = "";
}
}
if(flag){
document.writeln("<td><ul>" + (tmp.replace(/<td/g, "<li").replace(/td>/g, "li>")) + "</ul></td>");
}
}
document.writeln("</tr></tbody></table>");
»The full code and demo can be found in this jsFiddle.
I feel this is the wrong approach, it sucks in every way and more importantly, I can't have two or more consecutive groups!, after I start stacking columns, whenever I want to stop, the next column must be alone (and not another group).
I have played around with the booleans and it is simply impossible, I can't figure it out, I already reduced the code to the most readable way and tried to rewrite parts of it but I keep getting the same results.
I made a slight change to the data model. Instead of "toggle" the boolean says if the next guy stacks or not (that is if it is true then put the next one below me.)
So the data looks like this:
/*0:caption, 1:stack-toggler*/
cols[0][0]="Name";
cols[0][1]=true; //<--stack next below
cols[1][0]="Age";
cols[1][1]=true; //<--stack next below
cols[2][0]="[M/F]";
cols[2][1]=false;
cols[3][0]="E-mail";
cols[3][1]=false;
cols[4][0]="Website";
cols[4][1]=false;
cols[5][0]="Notes";
cols[5][1]=false;
And then the code can be simple -- like this (a trick I used, you can change the loop variable internal to the loop -- so we only loop on the outer loop when we change columns.)
for(i = 0; i < 20; i++){ //some number of rows
buildHTML("<tr><td>" + i + "</td>");
for(j = 0; j < cols_len; j++){
buildHTML("<td>");
if (cols[j][1]) {
buildHTML("<ul>"+cols[j][0]+"</ul>");
// loop till we are at the penultimate
while (cols[j+1][1]) {
j++;
buildHTML("<ul>"+cols[j][0]+"</ul>");
}
j++;
buildHTML("<ul>"+cols[j][0]+"</ul>");
}
else {
buildHTML(cols[j][0]);
}
buildHTML("</td>");
}
buildHTML("</tr>");
}
buildHTML("</tbody></table>");
I did not bother with the header, you can figure that out I'm sure.
Here is the fiddle:
http://jsfiddle.net/eajQy/3/
Of course with javascript you can get fancy. Since what you really have is an array of arrays for the columns you could represent that like this:
// array of arrays -- one element std, 2 or more a list
newcols = [ ["Name","Age","[M/F]"] , ["E-Mail"] , ["Website"], ["Notes"] ];
Then to make your table you could use map and join like this:
buildHTML("<tr><td>" + i + "</td>");
strArray = $.map(newcols, function (anArray) {
if (anArray.length == 1) {
return "<td>"+anArray[0]+"</td>";
}
else {
return "<td><ul>"+anArray.join("</ul><ul>")+"</ul></td>";
}
});
buildHTML(strArray.join(""));
buildHTML("</td></tr></tbody></table>");
Here is a fiddle:
http://jsfiddle.net/eajQy/4/
Single line solution (because every question should have a single line solution):
http://jsfiddle.net/eajQy/5/

Categories

Resources