Outputting numbers 1 to 100 onto a page - javascript

I'm new to web development. I need to output all numbers ranging from 1-100, each on a new line. The following code only outputs the last number:
var main = function() {
for(var i = 1; i <= 100; i++) {
$(".results").append("<p>").text(i);
}
};
$(document).ready(main);
While, this does exactly what I want it to:
var main = function() {
var $content;
for(var i = 1; i <= 100; i++) {
$content = $("<p>").text(i);
$(".results").append($content);
}
};
$(document).ready(main);
Why does the second solution work but not the first?

The issue with the first is that append() returns the parent element (the .results element) not the p which was appended to it. You are therefore updating the text property of .results on each iteration.
Note also that append() is a relatively expensive operation in terms of performance, so you can improve execution speed by rearranging your logic to only append once:
var main = function() {
var content = '';
for (var i = 1; i <= 100; i++) {
content += '<p>' + i + '</p>';
}
$(".results").append(content);
};

Related

Using getElementsByName in JavaScript, Number of elements keeps increasing in timed loop. Why?

This script is updating the images contained on a webpage without having to reload the page. That part works.
The part that doesn't is that the script seems to store the prior values of var obj and keeps accruing and appending the time so after a couple of passes, I end up with ...png?4314331?5847301?8978123 and it keeps appending.
So if my page has 5 images, after the first 5 seconds has passed, input.length will now be 10 and the second 5 seconds, input.length returns 15, and so on.
My question is why?
<script>
function updateImage() {
var input = new Array();
input = document.getElementsByName('imageChart');
for (var i=0; i < input.length; i++)
{
var obj = document.getElementsByName("imageChart").item(i);
alert(obj.src); // Just to check what it's doing
obj.src = obj.src + "?" + Math.random();
setTimeout("updateImage()",5000);
}
}
</script>
<body onload="updateImage()">
Don't know if it's the right way, but this is how I ultimately resolved all the issues.
<script type="text/javascript">
function updateImage() {
var input = new Array();
input = document.getElementsByName('imageChart');
for (var i=0; i < input.length; i++)
{
var obj = document.getElementsByName("imageChart").item(i);
var str = obj.src;
var strSplit = str.split("?");
obj.src = strSplit[0] + "?" + Math.random();
}
setTimeout(function() {updateImage()},10000);
}
</script>

Force begin rendering with javascript

I've an ajax-call that will give me a 500 row return. Each row will create a HTML-object that will be added to the DOM. This all works fine, but it's slow.
I would like to add 20, then render what is done, and then continue to add the last 480. However, I can't figure out how to force rendering.
The code is something like this:
for (i = 0; i < 500; i += 1) {
$(newdata[i]).insertAfter('#object');
}
Where newdata is a textstring, for example
"<p>hello world</p>"
Edit
I might have left out some critical information in my post. The nodes are not to be inserted in order. It's a tree and each node has a parent that I know about. And each parent is garanteed to be inserted before the node. So I can't just append nodes after eachother since they might be in different branches.
Stop inserting one node at the time, insert collections of nodes instead.
It's not the loop that's slow, it's DOM manipulation that is slow, and inserting 500 DOM nodes one node at the time will be slow.
var nodes = $();
for (i = 0; i < 20; i++) {
nodes.append(newdata[i])
}
$('#object').after(nodes);
var more_nodes = $();
for (i = 20; i < 500; i++) {
more_nodes.append(newdata[i])
}
$('#object').after(more_nodes);
If you do it like this, it will probably be ten times faster, and you don't have to insert 20, then 480 etc.
Give the rendering code time to run. Write a few rows, call setInterval() to let other code run, and continue:
function renderLines(newdata) {
var len = newdata.length;
var sofar = 0;
var obj = $('#object');
var renderSome = function() {
for ( var i = 0; (i < 20) && ((i + sofar) < len); ++i )
{
$(newdata[i + sofar]).insertAfter(obj);
}
sofar += 20;
if (sofar < len)
setTimeout(renderSome, 10);
};
setTimeout(renderSome, 10);
}

How do I relatively increment a CSS value on each iteration of a JavaScript for-in loop?

I'm trying to increment a margin-left value with each passing of a loop. How is this achieved?
Here's the JSFiddle and here's what I'm trying to do:
var myObj = {
"dog":"pony",
"sass":"tude",
"war":"peace"
};
for (i in myObj) {
$('#mainDiv').append("<p>" + i + "</p>");
$('p').css("marginLeft","++20px");
}
How to have each <p> tag incremented by 20px more than the <p> tag before it?
Change
$('p').css("marginLeft","++20px");
to
$('p').each(function() {
var thisp = $(this);
thisp.css("marginLeft", thisp.css("marginLeft") + 20);
});
You can use a variable outside of the loop to keep track of something incrementing. You also weren't properly getting the right p tag in your loop, if I'm understanding you correctly.
var myObj = {
"dog":"pony",
"sass":"tude",
"war":"peace"
};
var lastMargin = 0;
for (i in myObj) {
$('#mainDiv').append("<p class='"+i+"'>" + i + "</p>");
lastMargin += 5;
$("."+i).css("marginLeft",lastMargin+"px");
}
You obviously might want to use :nth-child with the i variable instead of classes.
Create a var that keep the count.
Also, only aim for the last p (last one added):
var myObj = {
"dog":"pony",
"sass":"tude",
"war":"peace"
},
count = 0;
for (i in myObj) {
$('#mainDiv').append("<p>" + i + "</p>");
$('p').last().css("marginLeft",(20 * count) + 'px');
count++
}
Fiddle : http://jsfiddle.net/3hxDK/4/
It seems like you're trying to have each subsequent paragraph indented more than the last?
If so, you need to reference the paragraph on its own.
var count = 0;
for (i in myObj) {
$("<p>" + i + "</p>").
css('marginLeft', count + "px").
appendTo($('#mainDiv'));
count += 20;
}

Improving speed of generating HTML table

Using jQuery .append I write some html to form a 10,000px grid of 125px X 80px. Where the pixels are numbered first down then across. Now this works fine but is slow enough that there's noticeable lag loading the page compared to writing it straight in html. Is it possible to speed this up at all while still maintaining the pixel numbering?
My html is:
<div id="grid">
</div>
Javascript:
function createGrid() {
var counter = 1;
var rowCounter = 1;
var divs = 10000;
$('<table width="625px"><tr>').appendTo('#grid');
for (var i = 1; i <= divs; i++) {
if (i % 125 == 0 ){
$('</ tr><tr>').appendTo('#grid');
rowCounter++;
counter = rowCounter;
}
else
$('<td id="pixel_' + counter + '" class="pixel"></td>').appendTo('#grid');
counter =+ 80;
}
$('</tr></table>').appendTo('#grid');
}
Your code won't work as you expect it to, because .append() creates complete DOM elements. $('<table width="625px"><tr>').appendTo('#grid') will automatically close both tags, and you'll have to append the next row to the table, and the cell to the row.
As it happens, it's inefficient to constantly append elements to the DOM anyway. Instead, build the table as a single string and write it out all at once. This is more efficient since you're only adding to the DOM one time.
function createGrid() {
var counter = 1;
var rowCounter = 1;
var divs = 10000;
var tstr = '<table width="625px"><tr>';
for (var i = 1; i <= divs; i++) {
if (i % 125 == 0) {
tstr += '</ tr><tr>';
rowCounter++;
counter = rowCounter;
} else
tstr += '<td id="pixel_' + counter + '" class="pixel"></td>';
counter = +80;
}
tstr += '</tr></table>';
$('#grid').append(tstr);
}
http://jsfiddle.net/mblase75/zuCCx/
$('<table width="625px"><tr>')
is not the same as writing and appending an HTML string! jQuery will evaluate that <table><tr> string and create a DOMElement from it. I.e., with just this tiny bit of code, you have created a whole table in the DOM. The closing tags are auto-completed and the table is instantiated. From then on you need to work with it as a DOM object, not as a string to append to.
Your code is probably slow because you're creating tons of incomplete/autocompleted tiny DOM objects which are all somehow being bunched together, probably not even in the correct structure. Either manipulate DOM objects, which should be pretty fast, or construct a complete string and have it evaluated once.
One of the first steps towards improving performance would be generating the complete HTML and appending to the DOM in one step.
function createGrid() {
var counter = 1;
var rowCounter = 1;
var divs = 10000;
var html = '<table width="625px"><tr>';
for (var i = 1; i <= divs; i++) {
if (i % 125 == 0 ){
html += '</ tr><tr>';
rowCounter++;
counter = rowCounter;
}
else
html += '<td id="pixel_' + counter + '" class="pixel"></td>';
counter =+ 80;
}
html += '</tr></table>';
$('#grid').html(html);
}

Read and Write JQuery Statements in One Loop

I have the following jQuery statement in a loop. #MainContent_gvDemographic and #tblFreez are two tables in a page.
$("#MainContent_gvDemographic").find(str)
.css("height", $("#tblFreez")
.find(str)
.css("height"))
When there are many steps in the loop, it takes a very long time to complete. To fix the problem, I then use two loops, one for reading the height of $("#tblFreez").find(str), the other for writing the height into $("#MainContent_gvDemographic").find(str), and use an array to carry the height data between the two loops. It becomes much faster now. Does anyone know why the two solutions have such big difference in performance? The computational complexity looks the same to me.
All right, here are the two complete version.
Original:
function FixHeight() {
var rowCount = $('#tblFreez tr').length;
for (var i = 0; i < rowCount; i++) {
var str = "";
if ($.browser.msie) {
str = "tr:eq(" + i + ") td";
}
else {
str = "tr:eq(" + i + ")";
}
$("#MainContent_gvDemographic").find(str).css("height", $("#tblFreez").find(str).css("height"));
}
}
New:
function FixHeight() {
var rowCount = $('#tblFreez tr').length;
var hei = new Array();
for (var i = 0; i < rowCount; i++) {
var str = "";
if ($.browser.msie) {
str = "tr:eq(" + i + ") td";
}
else {
str = "tr:eq(" + i + ")";
}
hei[i] = $("#tblFreez").find(str).css("height");
}
for (var i = 0; i < rowCount; i++) {
var str = "";
if ($.browser.msie) {
str = "tr:eq(" + i + ") td";
}
else {
str = "tr:eq(" + i + ")";
}
$("#MainContent_gvDemographic").find(str).css("height", hei[i]);
}
}
Why not use only one loop and not for but jQuery .each(). I haven't tested code below, but should work.
function FixHeight() {
var $MainContent = $("#MainContent_gvDemographic");
var $tblFreezRows = $("#tblFreez tr");
var hei, $row;
$tblFreezRows.each(function(index, elem){
$row = $(this);
if ($.browser.msie) {
hei = $row.find('td').css("height");
$MainContent.find("tr:eq(" + index + ") td").css("height", hei);
}
else {
hei = $row.css("height");
$MainContent.find("tr:eq(" + index + ")").css("height", hei);
}
});
}
The DOM operations are usually the expensive operations.
Your first version has heavy DOM operation, but your second version has the count. It looks like load vs number.
Ideally, your first version should be faster as it is just one loop and the number of iteration is half than the second version.. but it is not always the case.
Assume your memory is like 1000M in which 300M can be garbage collected meaning it can be cleaned up. So the Operating systems memory model would call the garbage collector whenever your memory gets closer to 1000M. With those conditions in mind, lets say in your first version, every 5 iterate takes 1000M, which would end up calling garbage collector to clean up or free up resources for next iteration. So if you end up running for 100 iteration which is equals to 100 iteration + 20 times GC processing.
In your second case, assume it take 50 iteration to fill up 1000M, so you would end up calling 4 time GC processing which is basically 20 vs 4 times calling some other process inbetween each of your iterate.
Above is just a speculation and the actual memory modules are much smarter than what I have explained, but that is just to give an idea of load vs numbers.
Anyways..Try below code and see if it fixes your problem,
Setting height at TR level
var fTable = document.getElementById('#tblFreez');
$("#MainContent_gvDemographic tr").each(function(ridx) {
$(this).height($(fTable.rows[ridx]).height());
});
Setting height at TD level
var fTable = document.getElementById('#tblFreez');
$("#MainContent_gvDemographic tr").each(function(ridx) {
$(this).find('td').each(function (cidx) {
$(this).height($(fTable.rows[ridx].cols[cidx]).height());
});
});
Try detaching the elements before you alter/search them. Then re-append them. DOM-operations are costly.

Categories