For some reason, the arithmetic in the function updateScore(result) doesn't work properly (the function is called later on in the code). wins, ties and losses are printed as they should, but lives is printed as NaN. I know what NaN means. I've also identified that the variables, for some reason or other, are created as strings. What appears strange to me, is that it's working for four out of five variables. There's no consistency. I've tried some number conversions using Number(lives), but that doesn't work either. Any suggestions to how I can ensure that the variables are created as numbers, and aritmethic operations will work?
var wins = 0,
ties = 0,
losses = 0,
lives = 5,
previouscpuChoice = 0;
$("#startknapp").click(function(){
var spiller = prompt("Hva heter du?");
$("#userSelect").html(userMenu);
$("#result").html("<h4>Velg figur, " + spiller + "</h4>");
$("#status").html('<h4>Liv: <span id="life">' +lives+ '</span> - Seire: <span id="win">' + wins + '</span> - Uavgjort: <span id="tie">' + ties + '</span> - Tap: <span id="lose">' + losses + '</span>');
console.log(typeof "lives");
console.log(typeof "wins");
});
function updateScore(result) {
tie = document.getElementById("tie");
win = document.getElementById("win");
lose = document.getElementById("lose");
lives = document.getElementById("life");
console.log(typeof "wins");
var imgSrc = "images/" + userChoice + "-" + result + ".png";
if (result === "tie") {
ties = ties + 1;
tie.innerHTML = ties;
$('.result-img').attr('src', 'images/tie.png');
}
if (result === "vant") {
wins++;
$('.result-img').attr('src', imgSrc);
}
if (result === "tapte") {
losses++;
lives--;
lose.innerHTML = losses;
life.innerHTML = lives;
$('.result-img').attr('src', imgSrc);
}
};
Have you tried the following?
var tie = parseInt(document.getElementById("tie").value);
Your current code:
document.getElementById("tie")
retrieves the DOM element rather than the value of the input. so you need to use .value and then you parse it as an integer as the inputs value is likely a string representation of the number you want rather than an integer value.
After pondering, I figured it's okay if the variables are strings, and looked at the code from a different perspective. And what do you know, it was a simple bug.
$("#startknapp").click(function(){
var spiller = prompt("Hva heter du?");
$("#userSelect").html(userMenu);
$("#result").html("<h4>Velg figur, " + spiller + "</h4>");
$("#status").html('<h4>Liv: <span id="life">' +lives+ '</span> - Seire: <span id="win">' + wins + '</span> - Uavgjort: <span id="tie">' + ties + '</span> - Tap: <span id="lose">' + losses + '</span>');
console.log(typeof "lives");
console.log(typeof "wins");
});
function updateScore(result) {
tie = document.getElementById("tie");
win = document.getElementById("win");
lose = document.getElementById("lose");
life = document.getElementById("life");
Originally the last line of updateScore(result) was:
lives = document.getElementById("life");
As a result two variables were mixed (the local one for the function (life) and the global one (lives). So in the end it was a typo. However, I'm still intrigued by the fact that a variable can be a string, and the value contained within an integer.
Related
I want to reverse my line order while keeping the style of words and the order I created.
HTML:
<textarea id="mytext"">
Buy - 3 Potatoes $6.25
Sold - 3 Napkins $7.12
Buy - 5 Fries $11.62
Sold - 7 Potatoes $14.32
</textarea>
<div id = "myresult"></div>
As you can see I did the order of words and style the words I just need to reverse the lines now.
I'm working on notepad++ and still pretty new to Javascript.
Script:
var mytext = document.getElementById('mytext');
var result = document.getElementById('myresult');
var lines = mytext.value.split('<br>');
result.innerHTML = '';
for(let i = 0;i < lines.length;i++){
var line = lines[i];
var list = [];
list.unshift(line);
list.unshift("<br>");
var word = line.split(' ');
var n1 = line.match(/[0-9]+/g);
var n2 = line.match(/[0-9]+\.[0-9]+/g);
var check = line.match(/Buy/);
var check2 = line.match(/Sell/);
if(check) {
result.innerHTML += "<span style='color:green;'>" + word[0] + "</span>" + ' ' + word[2] + ' ' + word[3] + ' total:$' + (n1[0]*[n2]).toFixed(2) + "<br>";
}
else if(check2) {
result.innerHTML += "<span style='color:blue;'>" + word[0] + "</span>" + ' ' + word[2] + ' ' + word[3] + ' total: $' + (n1[0]*[n2]).toFixed(2) + "<br>";
}
else {
result.innerHTMl + " ";
}
}
As you can see I already style the colors and fix the order. I just need to reverse the line and display it in innerHTML.
My idea was to make a array[], and then for every line in the for loop try to unshift the line and br but everytime it give errors sometimes it gives me a bunch of commas, and one time it it displays no colors or give me a bunch of random words.
Result should look like what is after the snippet run. This is what I want innerHTMl after the code is run. The code has to display innerHTMl inside the div please.
<div id="result">
<span style='color:blue;'>Sold</span> 7 Potatoes total: $100.24<br>
<span style='color:green;'>Buy</span> 5 Fries total: $58.1<br>
<span style='color:blue;'>Sold</span> 3 Napkins total: $21.36<br>
<span style='color:green;'>Buy</span> 3 Potatoes total: $18.75<br>
</div>
In continuation of my comment above, you could use js reverse() before anything else on creating new elements.
E.g.
var lines = mytext.value.split("\n").reverse();
I was given this task with some existing code to change the string color of each of three selector.value(s) that is output onto an input element to three different colors. The code boils the three selectors into a single output variable. Without destroying the code, I cannot figure out how to select each individual variables prior to condensing them.
If I could use the fontcolor() method, my life would be great but it's 2018 and I can't. Is there any way you can think of to solve this issue?To clarify, I need to alter the colors of the strings that belong to output(red), select1.value(blue) and select2.value(black.
Most of the action for this is happening in the parseOutput() function but I'm just stuck and don't think it's possible without rewriting the entire program.
function updateSelector(result){
var options = result.options;
var elementId = "select" + result.element;
var logger = document.getElementById('logger');
var selector = document.getElementById(elementId);
//logger.innerHTML = JSON.stringify(elementId);
selector.innerHTML = options;
selector.disabled = false;
}
google.script.run.withSuccessHandler(updateSelector).processOptions(0);
plate();
function resetAll(){
for (var i = 0;i<3;i++){
var selector = document.getElementById('select' + i);
selector.disabled = true;
selector.innerHTML = "";
}
google.script.run.withSuccessHandler(updateSelector).processOptions(0);
}
function finalSelection(){
var output = document.getElementById('out');
//output.focus();
output.select();
}
function plate(){
var plate = document.getElementById('plate');
plate.innerHTML = atob('Q3JhZnRlZCBieTogWmFjaGFyeSBTdGFjaG93aWFr');
}
//Adds the location as initial output, followed by divider, application, and issue if select1 is selected
//else statement added so if select0 is [Costco Website Name], to ommit the " - "
function parseOutput(){
var output = "";
if (select1.value.length > 0 && select0.value !== "[Costco Website Name]"){
output = output + ' - ' + select1.value + ' // ' + select2.value;
} else{
output = output + select1.value + ' // ' + select2.value;
}
out.value=output.trim();
}
And this is the Div that displays the output:
<div class="wide"><p><input class="wide" type="readonly" id="out" onfocus="this.select();"></p></div>
A modern replacement for fontcolor would use a span and a style (or class), e.g.:
function modernFontColor(str, color) {
return '<span style="color: ' + color + '">' + str + '</span>';
}
or
function modernFontClass(str, cls) {
return '<span class="' + cls + '">' + str + '</span>';
}
...where the class defines the styling.
This function is designed to report and increment the total (counter) for each specific obstacle.
function warningMaker( obstacle ){
var count = 0;
return function ( number, location ) {
count++;
alert("Beware! There have been " +
obstacle +
" sightings in the Cove today!\n" +
number +
" " +
obstacle +
"(s) spotted at the " +
location +
"!\nThis is Alert #" + count + " today for " + obstacle + " danger."
);
};
}
Now if I call the function by saying for example,
warningMaker("obstacleName1")(2,"locationName"); ===counter 1
warningMaker("obstacleName1")(2,"locationName"); ===counter still 1
But if I call it this way,
var obstacle1Maker = warningMaker("obstacleName1");
var obstacle2Maker = warningMaker("obstacleName2");
obstacle1Maker(2,"MiddleEarth");
obstacle1Maker(2,"Hogwarts");
obstacle2Maker(3,"Narnia");
The counter is incremented for every specific obstacle, how is this possible? I'm new to Javascript and I'm trying to grasp the concepts behind things like this.
Two different closures hold two different counters. You want sth like this:
var obstacles={};
function warningMaker( obstacle ){
var obstacles[obstacle] = obstacles[obstacle]||0;
return function ( number, location ) {
obstacles[obstacle]++;
alert("Beware! There have been " +
obstacle +
" sightings in the Cove today!\n" +
number +
" " +
obstacle +
"(s) spotted at the " +
location +
"!\nThis is Alert #" + obstacles[obstacle] + " today for " + obstacle + " danger."
);
};
}
Im storing all counts in a global object. Its therefore not dependent on closures etc...
Why your code doesnt work as expected:
warningMaker("obstacleName1");
This assembles a new function context ( function + closure ). It happens when you move a function out of its scope ( variable surrounding ). The function can still access it, as its bound to them ( called closure). So if you call that twice, you will create two different contexts with two different count variables...
I have a method called refreshHistory() that basically reads locally stored list of json (using https://github.com/marcuswestin/store.js/) and populates a list in the order they were stored at.
Everytime a user action happens, this method is called. But as the list gets bigger and bigger, it slows down the browser to a crawl.
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? 0 : store.get('history').history;
;
if (records == 0) {
$('#content #historyView').html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
$('#qtip-0-content #historyView').html(xhistory);
}
}
Rendering everything on every event is a simple strategy, which is good, but it does run into the performance problems you are describing. It's hard to give specific advice, but you could either:
Implement a more detailed rendering logic, where only new items are rendered and added to the DOM.
Use ReactJs or Virtual DOM libraries, which allow your code to use the render everything pattern, but make the actual updates to the DOM faster by doing the minimum needed.
The only way to really make this efficient is to implement it in a different way.
I've been using knockout.js personally and am very happy with it. Basically you write a template and the library handles the DOM node changes, only updating the parts needed. You will need to learn how to think slightly differently, but there are some great tutorials available.
That said, one simple trick you can try is move the selectors outside the function so they are only ran once instead of each time you call the function.
For sanity I would also keep records variable the same type whether or not the .get('history') returns undefined.
var contentHistoryView = $('#content #historyView');
var qtipHistoryView = $('#qtip-0-content #historyView');
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? [] : store.get('history').history;
if (records.length) {
contentHistoryView.html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
qtipHistoryView.html(xhistory);
}
}
I doubt this will have a huge impact though, as I suspect most of the execution time is spent in the loop.
I seem to somehow be losing the value of a variable im setting...
What im trying to do is not so important, so I've set up a (Well commented) jsFiddle to show you what im getting. Also the code is below.
If anyone can see whats going on any help is appreciated :)
See jsFiddle > http://jsfiddle.net/qNWuV/4/ < Recommend you take a look here
var habs = ["417,77", "410,363", "388,433", "262,435", "262,210", "391,101", "384,183", "61,114", "331,171", "164,433", "361,248", "302,329", "154,307", "410,350", "173,298", "308,429"]; //just an array of co-ords for another part of my app. Only the .length is used below.
//############################
// NOTE: as this problem depends on random numbers you MAY not see it. If "undefined" is ANYWHERE in the Result, the problem is occurring, otherwise re-run the code.
//############################
function link_habs(habs) {
var test2 = '';
var hab_length = habs.length;
for (var e in habs) {
var hab_link_1 = get_link(hab_length, e + ',');
var hab_link_2 = get_link(hab_length, e + ',' + hab_link_1);
document.write('<br /><br />each1: ' + hab_link_1); //Variable lost?
document.write('<br />each2: ' + hab_link_2 + '<br />'); //Variable lost?
test2 += e + ':' + hab_link_1 + ',' + hab_link_2 + '<br />';
}
document.write('<br /><br /><br />' + test2);
}
function get_link(count, not) {
var nots = not.split(',');
for (var i in nots) { nots[i] = parseInt(nots[i], 10); }
var hab_link = Math.floor(Math.random() * count);
if (nots.indexOf(hab_link) === -1) {
document.write('<br />returned: ' + hab_link); //Variable is intact HERE
return hab_link;
} else {
get_link(count, not);
}
}
link_habs(habs);
Cheers
Charlie
You are not returning the value from the recursive call.
Change:
get_link(count, not);
into:
return get_link(count, not);
In the get_link function, you are traversing the nots array using for / in. You should use a regular for loop.