I feel like I'm probably making a fundamental mistake here. I'm hoping someone can help me.
function countdown() {
x = 5;
for (i = x; i > 0; i--) {
document.getElementById('display').innerHTML = (i + " ");
}
}
This is a very small, simple replication of the problem I'm having.
I have a long function. Within that function is a variable, in this case: X.
I want to insert something into an element(in this case: #display) X amount of times.
I figured the best way to do this would be with a for loop, counting down from X by 1 and each time inserting the string I want.
But when it runs, it only returns 1. (I would expect it to return "5 4 3 2 1" in this case).
Please can someone explain to me why this doesn't work? I've been racking my brain over it for hours.
Because you are overwriting the content of the element in each iteration, by assigning a new value to innerHTML. You'd have to append instead:
document.getElementById('display').innerHTML += (i + " ");
// ^
which is the same as
document.getElementById('display').innerHTML =
document.getElementById('display').innerHTML + (i + " ");
And of course it would be much better if you just built the string in the loop and set the content after the loop:
var content = '';
for (i = x; i > 0; i--) {
content += (i + " ");
}
document.getElementById('display').innerHTML = content;
This way you avoid searching for the element in the document on every iteration. But .innerHTML is only useful to some degree, you should also have a look at DOM manipulation functions (such as .appendChild), once you are starting to do more evolved manipulations.
Related
I have tried for so long to get this code to work. I'm programming a little game when you need to be fast, so I made a stopwatch. But the stopwatch just doesn't want to work. Instead of the seconds the stopwatch is showing Object Undefined and I don't know why. This is the code i'm using:
var stopwatchFrame = 0;
var stopwatchSeconds = 0;
var stopwatchSecondsString = "Nothing";
stopwatchFrame+=1;
stopwatchSeconds = floor(stopwatchFrame/updatesPerSecond);
stopwatchSecondsString = toString(stopwatchSeconds);
var = "Total time: " + stopwatchSecondsString + " seconds";
I'm using a simple website called Koda.nu, it's a Swedish website for young to learn programming in JS. Some functions is coming from their built in source. I'm new to programming so that's why.
You are missing a variable name where you have a value of "Total time: " + stopwatchSecondsString + " seconds"; It should be:
var totalTime = "Total time: " + stopwatchSecondsString + " seconds";
Also read what #Jaromanda X wrote in the comments section. It should be like this:
stopwatchSeconds = Math.floor(stopwatchFrame/updatesPerSecond);
stopwatchSecondsString = stopwatchSeconds.toString();
We don't have an access to your updatesPerSecond variable so that would throw an error as well. If declared, your code would work like this:
var stopwatchFrame = 0;
var stopwatchSeconds = 0;
var stopwatchSecondsString = "Nothing";
var updatesPerSecond = 0;
stopwatchFrame += 1;
stopwatchSeconds = Math.floor(stopwatchFrame / updatesPerSecond);
stopwatchSecondsString = stopwatchSeconds.toString();
var totalTime = "Total time: " + stopwatchSecondsString + " seconds";
You dont have a variable name in the last line, and if this is all your code, then you dont initialize updatesPerSecond, meaning you dont have a line like
var updatesPerSecond = somenumberhere
If you name your last variable and initialize updatesPerSecond then you should be fine.
However I dont know anything about this website, but I quess it's old. Here is some advice.
You need to tell javascript, that floor is a function from Math so use Math.floor, maybe it works in this website like you did, but keep in mind that you should use it otherwise.
toString() doesnt work like that. Again I dont know if they are using some different methods, but normal js toString() works like number.toString() and u can pass the radix as a parameter, meaning the base of the number representation (2 for binary, 16 for hexadecimal etc.) but this is optional, default is 10 for decimal.
Dont use var as a declaration. Use let instead, if the variable will change, and use const if it wont. In your case you should use let everywhere.
Other thing is that you can use the ++ operator to increment a value by 1, so instead of stopwatchFrame+= 1 just use stopwatchFrame++
And last you shouldn't initialize your default string value as "Nothing", it should be "", an empty string or undefined or null.
I hope this helps, have a good day!
i could not make it as function.Please help.When i modified as function and add button,it not work.
i'm newbie in javascript.i would like study by the simple script.But for the below script when i try to add "function xxx()" it not working with input button.
I try to solve by my own with google...failed.
<script>
var myStr = "xxx yyy zzz";
var strArray = myStr.split(" ");
// Display array values on page
for(var i = 0; i < strArray.length; i++){
document.write("<p>" + strArray[i] + "</p>");
}
</script>
Break your code into blocks if you ever are stuck on something. So first you are trying to break a string into an array so that's your first block. Then your second block would be to write it to the page. So we have our code basically written out in our heads.
---Break string
---Display broken string
So to make a function we need to write a function first
myFunction = function(){
};
But to get the function to be modular we need to be able to pass in variables
So we'll add two variables one being the string to pass through and one being the location to inject the looped broken text.
myFunction = function(str, location){
};
Now we have to do something with these variables.
myFunction = function(str, location){
///test if str is a string
if(typeof(str) == "string")
{
var l = str.split(" "); /// here we're spliting the string into an array by every space
if(l.length >= 1) ///test if there's atleast one item
for(i=0;i<l.length;i++) ///simple for loop
location.innerHTML += "This is a part of str " + l[i] + "<br>" ///you can do anything here you want to do.
}
};
Now as you can see it's modular at it's lowest point, this can be as complex as you want it. here is a test you can try out and mess around with. https://jsfiddle.net/s8pytzm3/1/
This probably is a very easy solution, but browsing other questions and the internet did not help me any further.
I made a javascript function which will give me a random value from the array with its according points:
function random_card(){
var rand = Math.floor(Math.random()*cards.length);
var html = "card: "+cards[rand][0]+"<br/>points: "+cards[rand][1]+"<br/><br/>";
document.getElementById("Player").innerHTML += html;
var punten = cards[rand][1];
document.getElementById("Points").innerHTML += punten;
}
I've added a += punten so i can see that it works correctly. It shows me all the point in the div with the id Points.
But what i wanted to do is count it all together so if i were to draw a 4, King and a 10 it should show 24 instead of 41010.
Thanks in advance! And if you're missing any information please let me know
Currently you are just adding strings together, which concatenate (join together) hence why you end up with 41010. You need to grab the current innerHTML (total) and use parseInt() to convert from a string to a number, then add your new cards that have been chosen, then assign this new value to the innerHTML of your element.
Try the following
function random_card(){
var rand = Math.floor(Math.random()*cards.length);
var html = "card: "+cards[rand][0]+"<br/>points: "+cards[rand][1]+"<br/><br/>";
document.getElementById("Player").innerHTML += html;
var punten = cards[rand][1];
var curPoints = parseInt(document.getElementById("Points").innerHTML, 10) || 0;
var total = curPoints + parseInt(punten, 10);
document.getElementById("Points").innerHTML = total;
}
More info on parseInt() here
EDIT
I've added this line -
var curPoints = parseInt(document.getElementById("Points").innerHTML, 10) || 0;
Which will try and convert the innerHTML of the "Points" div, but if it is empty (an empty string converts to false) then curPoints will be equal to 0. This should fix the issue of the div being blank at the start.
innerHTML is a string and JavaScript uses + for both string concatenation as numeric addition.
var pointsInHtml = parseInt(document.getElementById("Points").innerHTML, 10);
pointsInHtml += punten;
document.getElementById("Points").innerHTML = punten;
The second parameter 10 of the parseInt method is usually a good idea to keep there to avoid the function to parse it as an octal.
It might be easier to keep a points variable and only at the end put it in the #Points container, that would make the parseInt no longer necessary
innerHTML will be a string, so you need to convert it into an integer prior to adding the card value :)
function random_card(){
var rand = Math.floor(Math.random()*cards.length);
var html = "card: "+cards[rand][0]+"<br/>points: "+cards[rand][1]+"<br/><br/>";
document.getElementById("Player").innerHTML += html;
var punten = cards[rand][1],
curPunten = parseInt(document.getElementById('Points').innerHTML);
document.getElementById("Points").innerHTML = curPunten + punten;
}
I'm loading SELECT element with 6000 items using createElement and add methods. The code is shown below, and can also be accessed here. In IE8 it takes around 16 seconds to load the list and about the same time to clear it. In IE9 and Firefox the loading time is < 2 seconds and clearing time is < 1 second. Any ideas on how I can improve the speed in IE8?
Thank you.
<script type="text/javascript">
window.onload = loadList;
function loadList() {
clearList();
var start = new Date().getTime();
var o = document.getElementById("listLookupAvailableItems")
for (var i = 0; i < 6000; i++) {
var option = document.createElement("option");
option.text = 'ABCDF ' + i;
option.value = option.text;
o.add(option, o.options[null]);
}
log('Load time: ' + (new Date().getTime() - start));
}
function clearList() {
var start = new Date().getTime();
document.getElementById("listLookupAvailableItems").options.length = 0;
log('Clear time: ' + (new Date().getTime() - start));
return false;
}
function log(txt) {
document.getElementById('infoPanel').innerHTML += '</br>' + txt;
}
</script>
My guess is that that particular DOM operation is just really slow in IE8. In general, manipulating the DOM is the slowest type of operation in any browser. To get around that I typically try to find ways to combine my changes into one DOM update (e.g. add an HTML "batch" of 6000 rows to a table instead of individually adding 6000 rows to a table).
In this example the only way to do that would probably be to create all of the <option> elements as HTML and then use innerHTML to insert them into the <select>. See this jsfiddle example: http://jsfiddle.net/pseudosavant/bVAFF/
I don't have IE8 to test with, but it is much faster even in Firefox (22ms vs 500ms) for me.
Update
Looks like it didn't work with innerHTML in IE for loading the list, but it did work for clearing it. Loading it works using jQuery $(o).html(html); though. I updated the jsfiddle example and it works in IE9, and hopefully IE8 now.
Javascript:
$(document).ready(function(){
loadListBatch();
});
function loadListBatch() {
clearListBatch();
var start = new Date().getTime();
var o = document.getElementById("listLookupAvailableItems")
var html = "";
for (var i = 0; i < 6000; i++) {
html += "<option value='"+'XYZ' + i+"'>"+'XYZ ' + i+"</option>";
}
// o.innerHTML = html; // Only one DOM operation, but still doesn't work in IE
$(o).html(html); // Using jQuery to insert the HTML makes it work with IE
console.log('Load time: ' + (new Date().getTime() - start));
}
function clearListBatch() {
var start = new Date().getTime();
document.getElementById("listLookupAvailableItems").innerHTML = ""; // It was already only one DOM call, but this is faster it seems.
console.log('Clear time: ' + (new Date().getTime() - start));
return false;
}
If you are supporting IE7/IE8 you should minimize JavaScript manipulation of the DOM. So if you are appending, inserting or deleting nodes you need to minimize DOM manipulation in general. The best solution is to bulk update items.
So, if you have a select list and you are doing JQuery.append() you will get better performance if you concatenate your entire options string before appending.
var str = $('<option value="x">Item 1</option>' + '<option value="y">Item 2</option>');
$('#selectMenu').append(str);
//or in a loop
var array = ['orange','apple','grapes','mangoes'];
var str = '';
for (var x= 0; x < array.length; x++) {
str = str + '<option value="' + x + '">' + x + '</option>';
}
$('#selectMenu').append(str);
Additionally, if you want to see how slowly JavaScript is executed by IE8 run the SunSpider JS test. Firefox 22 and Chrome 27 are around 300 ms while IE8 is around 4,000 ms. That tells a lot about why your JS speeds are slow. Interestingly IE10 comes in at less than 200 ms now. http://www.webkit.org/perf/sunspider/sunspider.html
I had a very similar situation.
I have a set of inputs with 1700+ so I provided a "filter" option that would copy the select and apply a filter based on a besides the copied list. (It "opens" a dialog that expands the dropdownlistbox to a list almost as big as 80% of the screen)
Copying the worked unnoticeably in other browsers but took 8-15 secs in IE.
The solution, based on previous answers, and also based on this post (Learn the slow (and fast) way to append elements to the DOM) was to add all the items to a HTL string, then assigning this to the innerHTML of a new object, one that is not yet part of the DOM. And finally, replacing the object from the DOM with the new one.
This apparently reduces the number of "reflow" operations performed by the browser, which is most likely the culprit of such slow performance.
Some of the test before implementing this style, was to run the full for loop without adding the options to the list, and in such test, the code executed very fast, it was clear that selectElement.add(optionElement) was the slow part.
Here is an example of what my function ended like:
function fillselector(IdSelect){
var selector = document.getElementById(IdSelect);
if( !selector ){
alert('Original select element not found.');
return;
}
var lista = document.getElementById('selectFilter_lista');
if( !lista ){
alert('Copied list element not found.');
return;
}
var filterText = noSpecialChars(document.getElementById('selectFilter_text').value);
var options =''
for (var i = 0; i < selector.length; i++){
if (filterText == '' || noSpecialChars(selector[i].text).indexOf(filterText) != -1 ){
//Commented code works but is painfuly slow on IE
//var option = document.createElement("option");
//option.value = selector[i].value;
//option.text = selector[i].text;
//lista.add(option);
options += '<option value="'+selector[i].value+'">'+selector[i].text+'</option>';
}
}
var newList = document.createElement('select');
newList.id='selectFilter_list';
newList.className='selectFilter_list';
newList.size = 20;
newList.ondblclick= function(){closeselector(IdSelect, true);}
newList.innerHTML = options;
newList.value = selector.value;
var listParent = lista.parentElement; //<div> that only contains the <select>
listParent.removeChild(lista);
listParent.appendChild(newList);
}
Ok I've been asking alot of JS questions lately, and realized I just need to go learn it.
Been following tutorials at http://www.tizag.com/javascriptT very simple and straightforward.
I just want to make sure I understand this correctly. It took me a while to get it:
<script type="text/javascript">
var myString = "zero one two three four";
var mySplitResult = myString.split(" ");
for(i = 0; i < mySplitResult.length; i++){
document.write("<br /> Element " + i + " = " + mySplitResult[i]);
}
</script>
-
var myString = "zero one two three four";
Obviously that creates a simple string variable.
var mySplitResult = myString.split(" ");
That splits it using " " as the delimeter, and assigns it to the mySplitResult array. Correct? Or is it not an array?
for(i = 0; i < mySplitResult.length; i++){
Is this saying the number of values in the array? Doesn't seem like it could be saying the actual length of characters in the string.
document.write("<br /> Element " + i + " = " + mySplitResult[i]);
This just returns mySplitResult[i] variable "i". Since i is increasing with each loop, it pulls the correct information from the array.
Your understanding is essentially correct. One thing you should do is declare all your variables: this is particularly important inside functions. So, you should declare i as a variable, either before the loop:
var i;
for (i = 0; i < mySplitResult.length; i++) {
... or in the first expression in the for statement:
for (var i = 0; i < mySplitResult.length; i++) {
Your analysis is correct, but you should see that by just testing it. Use Firebug extension with Firefox and you can step through your javascript.
This will help you understand what is going on, as you can then look at properties of the element and monitor what is actually happening.