Why does my JavaScript code not work on refresh? - javascript

I'm taking a Udemy course and one of the exercises is to build a Dice game.
Basically it's just two dice (for each player/stakeholder) on screen both showing the value of 6. On refresh, it should 'roll' the dice (generate a random side for each dice, which are all images), and the header text should change to state the outcome of the game.
But my code doesn't work on refresh. I'm trying to find out why. Here's a comparison of my code VS the instructor's code:
This is my code, which doesn't work on refresh (but I've tested it and it works when I run it as a function).
//Generating Random Numbers for Dice 1 & Dice 2
var RandomNo1 = (Math.floor(Math.random() * 6) + 1)
var RandomNo2 = (Math.floor(Math.random() * 6) + 1)
//Making a var for image sources Dice 1-6 (images/dice#.png)
var imageSource1 = ("images/dice" + RandomNo1 + ".png")
var imageSource2 = ("images/dice" + RandomNo2 + ".png")
//set.Attribute function to change the img source for the dice
document.querySelector('.player1').setAttribute("src", imageSource1);
document.querySelector('.player2').setAttribute("src", imageSource2);
//Setting conditional statements to change the header depending on results of the dice roll.
if (RandomNo1 > RandomNo2) {
document.querySelector("h1").innerText="Player 1 Wins!";
}
else if (RandomNo2 > RandomNo1) {
document.querySelector("h1").innerText="Player 2 Wins!";
}
else {
document.querySelector("h1").innerText="It's a draw!";
}
This is the instructor's code, which does work on refresh.
var randomNumber1 = Math.floor(Math.random() * 6) + 1; //1-6
var randomDiceImage = "dice" + randomNumber1 + ".png"; //dice1.png - dice6.png
var randomImageSource = "images/" + randomDiceImage; //images/dice1.png - images/dice6.png
var image1 = document.querySelectorAll("img")[0];
image1.setAttribute("src", randomImageSource);
var randomNumber2 = Math.floor(Math.random() * 6) + 1;
var randomImageSource2 = "images/dice" + randomNumber2 + ".png";
document.querySelectorAll("img")[1].setAttribute("src", randomImageSource2);
//If player 1 wins
if (randomNumber1 > randomNumber2) {
document.querySelector("h1").innerHTML = "🚩 Play 1 Wins!";
}
else if (randomNumber2 > randomNumber1) {
document.querySelector("h1").innerHTML = "Player 2 Wins! 🚩";
}
else {
document.querySelector("h1").innerHTML = "Draw!";
}
How does her page change on refresh? Why doesn't it change immediately upon loading? Why doesn't my code, like hers, work on refresh?

Your script is fine. In essence it does the same as the script your teacher provided. To be honest, your script is better on several aspects, not in the least because you have added explanatory comments throughout, and I really like to see someone using .innerText, and not .innerHTML. The latter is really intended to inject HTML, so you did right to opt for .innerText. Personally, I would use .textContent, but that is just a detail.
The only explanation that is left, is that your script runs too soon, when the DOM is not ready yet, and so the querySelector() calls return undefined.
Move your <script> element towards the end of your HTML document, after the other elements you need to address in your script. A good place to put it, is right before the closing </body> tag.

welcome to stackoverflow!
There are a few mistakes in your code:
Do not begin your variable names with capital lettes, these are for naming constructors. (It's some sort of unspoken law to make your code better readable for other developers as well)
I don't think this is a problem in your code you showed us. I think you should
paste the script tag on the end of the html file, so document.querySelector() can select the html elements.
I made a pen here where I took your code and show you that it works. (I just changed the $element.setAttribute("src") to $element.innerText)
You can also use $element.src = instead of $element.setAttribute("src")

Related

How to run a specific javascript code before page load (first of all)?

I have a js code that adds margin-top to a row with a specific class name (page with id=3) . I would like this code runs before page load because now it instantly displays the row without margin-top and then add it. The row should be displayed with the margin-top already be added.
My site is on wordpress and i added the js script on head.
I have tried
window.onpaint = checkMargin();
but it did not work. Any idea?
This is my js code
<script type="text/javascript">
//sets margin-top in serv-col --- IF not mobile version
function addServMargin() {
containers = document.getElementsByClassName('serv-cont');
titles = document.getElementsByClassName('serv-col-title');
texts = document.getElementsByClassName('serv-col-text');
links = document.getElementsByClassName('serv-col-link');
col_pad = '0px';
if ( window.innerHeight > 800) { col_pad = '8.3vh'; }
for (var i = 0; i < titles.length; i++) {
title_height = titles[i].offsetHeight;
text_height = texts[i].offsetHeight;
style = window.getComputedStyle(containers[i], '');
cont_height = style.getPropertyValue('height');
cont_padd = style.getPropertyValue('padding-top');
links[i].style.marginTop = 'calc(' + cont_height + ' - ' +
cont_padd + ' - ' + col_pad + ' - ' + title_height + 'px - 1.48vh - ' +
text_height + 'px - 127px - 5vh)';
}
}
function checkMargin() {
if (document.getElementsByClassName('page-id-13')[0] && window.innerWidth > 900) { addServMargin(); }
}
window.onresize = checkMargin;
</script>
I don't think making it run first will solve anything. The first thing the code does is get the containers, titles, texts, and links... which it does by searching the DOM. It then loops through the titles array and does the adjusting as needed. If the script runs before any rendering is done, the DOM elements won't exist. It 1) won't be able to find them, and 2) can't loop through them because the array will be empty.
Actually even before that, it checks for the existence of the elements it's looking for, and the screen size. I think the only way to get it to work w/o making it look like an after thought adjustment, would be to use CSS and media sizing to set the styles in the first place.
As I know JS is executed as the script tag is reached by Browser html interpreter. So putting it in the head tag on the first position may guarantee that it strats first, but can't guarantee that it ends execution before page loads, because the page loads asynchroniously.

JavaScript to toggle relay through website

I apologize I am new to javascript. I am trying to toggle a relay from a website using setInterval. The relay is a Sainsmart with 16 channels and it is connected to an arduino controlled by a raspberry pi. The goal is to eventually have three independent relays toggling at particular intervals. However, every attempt to get the first one working fails. In addition, every time I add a setInterval within a function or global, freezes the live streaming video from my ip camera. I am using a sandbox key through ably.
The html code and script work to toggle the relay on, and then a second button will toggle it off, but I need a single button to accomplish it.
The button initiates the sequence with a counter dictating whether the relay toggles on or off. It is set up to toggle on with an even number and off with an odd number. Any help would be greatly appreciated.
Here is the updated code I am trying to work with.
<div class="grid-item"><button id="37" onclick="startOnOff()">Start</button>
</div>
<script src="http://cdn.ably.io/lib/ably.min-1.js"></script>
<script>
var count = 0;
function startOnOff() {
var on = "37" + "on";
var off = "37" + "off";
if (counter % 2 == 0) {
toggleRelay(on);
count += 1;
} else if (count % 2 == 1) {
toggleRelay(off);
}
setInterval(startOnOff, 2000);
}
You have count in a few places and counter in one place where it should be count.
Assuming toggleRelay() is defined somewhere else in your code, try this:
var count = 0;
var on = "37" + "on";
var off = "37" + "off";
function startOnOff() {
if (count % 2 == 0) {
toggleRelay(on);
} else {
toggleRelay(off);
}
count += 1;
setTimeout(startOnOff, 2000);
}
count += 1; should be outside of the if conditional statement,
and use setTimeout() when calling startOnOff() recursively.

Unable to modify javascript within an HTML website

Hello I am relatively new and have never coded before a month ago but I am slowly teaching myself the structure and inner workings of a website though html, css, and javascript. I am trying to modify a specific script within a website. This website is
https://www.wizards.com/dnd/dice/dice.htm
My goal is to make it so that I can manipulate a dice roll to give me an altered range for example instead of 1-4, maybe 1-10 and to also perhaps give me a number I specify. I also want to leave the general aesthetic of the site as unchanged as possible.
So first off I put this handy piece of code within the URL
javascript:document.body.contentEditable='true'; document.designMode='on'; void 0
and it allowed me to make the content within the body editable.
I wanted to be simple and just change the D4 dice element https://gyazo.com/adf563827f63edd37264882e90fd5f85 so it would give give me numbers in a range of 1-20.
The HTML code for this element is
<img src="https://www.wizards.com/dnd/dice/images/d4a.jpg" alt="d4" name="d4" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('document.d4','document.d4','images/d4b.jpg')" width="38" border="0" height="37">
I noticed the onclick="rolld4()" So I looked within the head of the website and noticed within <script language="JavaScript1.2"></script> these lines of code.
function rolld4() {
d4rolls = parseInt(document.form1.d4n.value);
d4mod = parseInt(document.form1.d4mo.value);
dtotal = "";
d4res = 0;
rtotal = document.form1.runningtotal.value;
for (i=0; i<2; i++) {
if (document.form1.d4m[i].checked) {
d4pm = i }
}
if (d4pm == 0) {
dtotal = dtotal + "Roll(" + d4rolls.toString() + "d4" + ")+" + d4mod.toString() + ":\n"
}
if (d4pm == 1) {
dtotal = dtotal + "Roll(" + d4rolls.toString() + "d4" + ")-" + d4mod.toString() + ":\n"
}
for (r=0; r<d4rolls; r++) {
var d4 = Math.floor((Math.random() * 4) + 1);
d4res = d4res + d4;
dtotal = dtotal + d4.toString() + ","
}
if (d4pm == 0) {
d4res = d4res + d4mod;
dtotal = dtotal + "+" + d4mod + "\n" + "Total:" + d4res
}
if (d4pm == 1) {
d4res = d4res - d4mod;
if (d4res <= minimumvalue) {
d4res = minimumvalue;
}
dtotal = dtotal + "-" + d4mod + "\n" + "Total:" + d4res
}
document.form1.d4r.value = d4res;
rtotal = dtotal + "\n\n" + rtotal;
document.form1.runningtotal.value = rtotal;
}
I altered above line Math.floor((Math.random() * 4) + 1) to Math.floor((Math.random() * 20) + 1)
I then created a new script with the modified code and placed it below the D4 dice element which should alter the output to give me my range from 1-20. I was able to achieve a bit of success and did in fact mimic a roll range of 1-20. However this has only worked for me once and I have been unable to replicate it even going through the exact same process.
I also saw that within the <script language="JavaScript1.2"></script>scripts that it was one large comment. This is what confuses me because if the javascript functions within the code are turned to comments where is the javascript being pulled from when the dice is clicked and "rolled". I cant seem to find the source.
I am a total novice when it comes to javascript I have mostly been delving into HTML and CSS for designing websites so I have practically zero knowledge of javascript beside the general format.
You cannot alter (change) or delete any javascript on a loaded website. It's not possible as web browsers first compile the javascript when website is loading and prepare it for execution.
Even if you delete a script tag, that piece of code exists somewhere in the memory.
BUT, you can add pieces of javascript code to a webpage (think of it as it is adding itself to the end of the page in a separate script tag) via web console or Scratchpad in Mozilla Firefox OR developer tools > console in Google Chrome.
With that and some clever thinking (depending on the existing code on the website) you can do the stuff you want.

drawImage on HTML5 canvas is not working

I'm creating a 'catch falling items' game, and have successfully drawn the 'catcher' image and the 'falling items' images onto the canvas. But I'd like to also show an image (x.png) when a falling image is not caught and hits the base of my html5 canvas. The generateX function is called from the animate function and when a falling image hits the base of the canvas. The sound.play() is working. The console.logs in the generateX function log the following - 2,3 | 1,3 | 1,3 - so I know that the image is not completely loaded the first time this function runs. Everything seems to be working EXCEPT for the actual image displaying. I tried to structure it in ways that other threads have suggested, but nothing is working. Any help is much appreciated!
generateX: function() {
console.log('inside generateX func');
var imgX = new Image();
imgX.src = 'assets/x.png';
function drawX() {
console.log(3);
counter+=20;
context.drawImage(imgX, xIcon.x + counter, xIcon.y, xIcon.width, xIcon.height);
xArr.push(imgX);
console.log('xArr', xArr);
}
if (imgX.complete) {
console.log(1);
drawX();
} else {
console.log(2);
imgX.onload = drawX;
}
helper.checkMisses();
}
animate: function() {
var sound;
if (continueAnimating) {
requestAnimationFrame(helper.animate);
}
for (var i = 0; i < surveys.length; i++) {
var survey = surveys[i];
if (helper.isColliding(survey, dinoSaurus)) {
sound = new Audio("audio/coinSound.mp3");
sound.play();
score += 5;
helper.resetSurvey(survey);
}
survey.y += survey.speed;
// if the survey is below the canvas,
if (survey.y > canvas.height) {
sound = new Audio("audio/buzzerSound.mp3");
sound.play();
helper.generateX();
helper.resetSurvey(survey);
}
}
// redraw everything
helper.drawAll();
}
--
resetSurvey: function(survey) {
// randomly position survey near the top of canvas
survey.x = Math.random() * (canvas.width - surveyWidth);
survey.y = 40 + Math.random() * 30;
survey.speed = (0.55 + Math.random()) * 0.9;
}
Try loading your image earlier
If I understand your situation correctly, I think the issue is that you need to load the image earlier so that it is easily ready by the time you want to draw it, rather than waiting to load it only inside generateX. The way you are currently coding it, you are loading the image (imgX.src = ...) and then immediately trying to draw it. True, you are checking if the loading is complete and, if not, trying again shortly after. However, a better strategy is to load the image much earlier, e.g. during game initialization.
Demo
The code snippet below demonstrates the difference that this makes. It loads 2 different images. The only difference between the two is that one (on the left) is loaded ahead of time and the other (on the right) is only loaded inside generateX. The former image displays properly the 1st time through the game cycle while the latter image is missing the 1st time and only displays properly the 2nd time through.
function loadLeftImageWellBeforeRunningGenerateX() { // correct timing
imgs[0] = new Image();
imgs[0].src = 'http://placehold.it/200x100.png';
}
function loadRightImageInsideGenerateX() { // incorrect timing
imgs[1] = new Image();
imgs[1].src = 'http://placehold.it/100x50.png';
}
function generateX() {
loadRightImageInsideGenerateX();
log('--inside generateX func');
imgs.forEach(function(imgX, num) { // same as your original code, just done for 2 different images
if (imgX.complete) {
log("----image #" + num + " (" + side[num] + "); " + 1 + ", i.e. image complete");
drawX(imgX, num);
} else {
log("----image #" + num + " (" + side[num] + "); " + 2 + ", i.e. image not complete");
imgX.onload = drawX(imgX, num);
}
});
}
function drawX(imgX, num) { // same as your original code, just allows placement of 2 images side-by-side
log("----image #" + num + " (" + side[num] + "); " + 3 + ", i.e. drawing image (" + prefix[num] + "successfully)");
context.drawImage(imgX, num * 150 + 10, 10, 100, 50);
if (num === 1) {prefix[1] = "";}
}
var
imgs = [],
numClicks = 0,
side = ["left", "right"],
prefix = ["", "un"],
button = document.querySelector("button"),
canvas = document.getElementById('myCanvas'),
context = canvas.getContext('2d');
context.fillStyle = "yellow";
context.fillRect(0, 0, 300, 150);
// as far as game logic goes, the only important lines below are marked with arrows
// the rest is just "fluff" to make the demo more understandable to the user
button.addEventListener("click", function() {
numClicks += 1;
if (numClicks === 1) {
log("You must clear your browser's recent cache every time you run this snippet " +
"in order for it to demonstrate the problems and solutions " +
"associated with loading images in this code.");
button.innerHTML = "Clear browser cache and click here again to start game initialization";
} else if (numClicks === 2) {
loadLeftImageWellBeforeRunningGenerateX(); // <----- ***
log("Game initializes. No images should yet be visible, " +
"but image #0 (left) should be loading/loaded now, i.e. ahead of time. " +
"Image #1 (right) is not yet loading/loaded. Click again to 'play game'.");
button.innerHTML = "Do NOT clear the browser cache and click here again to start playing game";
} else {
button.innerHTML = "Do NOT clear the browser cache and click here again to continue playing game";
if (numClicks === 3) {
log("Game begins. Images are required for the first time. Only the pre-loaded left image shows " +
"even though loading both is attempted.");
} else {
log("Game continues. On second and subsequent re-draws, both images are now available and visible.");
}
generateX(); // <----- ***
}
});
function log(msg) {
document.body.appendChild(document.createElement("p")).innerHTML = msg;
}
p {
margin: 0.2em;
}
<canvas id="myCanvas" width="300" height="80"></canvas>
<div>
<button>Click here to begin demo</button>
</div>
Your browser's cache can hide this bug
By the way, if and when you try to debug this kind of thing, be aware that many/most/all browsers cache images, making it potentially difficult to replicate this kind of bug if you're not aware of what's going on. For example, you might run your buggy code and the image is missing the first time through the game cycle. You study your code, make a change to try to fix the bug and run the code a second time. Voila, it looks like the problem is fixed because the image now appears the first time through the game cycle. However, it may, in fact, only be showing up in that first cycle not because the bug is fixed but because the browser is able to use the cached image even in the first game cycle, eliminating the need to load it from its source. In short, if you're trying to debug an issue like this where you suspect the timing of file loading is important but the bug only appears sometimes, try clearing your browser's recent cache to see if that makes the bug more apparent.
To clear a browser's cache:
Firefox (for Mac or Windows, v44...): click "History" / click "Clear Recent History..." / click to open "Details" if necessary / check "Cache" / click "Clear now"
Chrome (for Mac, v48...) "Chrome" (left menu item) / "Clear Browsing Data..." / select "Cached images and files" / click "Clear browsing data"
Chrome (for Windows, v48...) click customize-and-control icon (at the right) / click "More tools..." / click "Clear browsing data..." / click "Clear browsing data"
Internet Explorer (for Windows, v11...) click "Tools" / click "Delete browsing history" / select "Download history" / click "Delete"

Can I put a variable = another variable in if statements. Or put var = value = another value which it should be equal to?

Hi I'm trying to work on a problem solving webpage that I need for school but so far I'm stuck with the if statement which it will use to calculate.
What I have so far.
<script>
var randomNumberA = Math.round((Math.random() * 50) +1)
var randomNumberB = Math.round((Math.random() * 50) +1)
document.write('He runs at ' + randomNumberA + 'm/s which took him ' + randomNumberB + 's. How far did he run?');
var distance = randomNumberA * randomNumberB
function Submit()
{
var answer = document.getElementById('answer')
if(distance == true){
alert("Congrats! You got it right!");
} else{
alert("Try again!");
location.reload();
}
}
</script>
<body>
<input type='text' id='inputAnswer'/>
<input type='button' onClick='Submit()' value='Submit'/>
</body>
It's not really working and if I put only one "=" then it'll alert as true as long as there's a value in the text box. I plan to make a variable for the textbox value and a variable for the formula and just put If(var1=var2)... so on, but it doesn't work. I'd like to know if it's possible, and if it is how?
If it's not possible can I try to place var1 = formula = textbox id. I'm trying to make it so one variable contains the values that need to be equal so when I declare it in the if statement, I'll just test if it's true or false.
All help is appreciated thanks!
You should compare the calculated distance to the given answer. Now you compare distance to true, which doesn't make sense.
Change it to
if(distance == parseFloat(answer.value)){
You need .value, because answer points to the element. You don't want to compare distance to the element, but to the numeric representation of the element's value.
Also note that you have the id wrong. In html it is inputanswer, while in your script you called it answer.
The version with a single = works, because you assign a value to distance. An assignment can also be used as an expession, which returns the value that was assigned. So if you write if (distance = true), you assign true to the variable distance, and also return true from the expression, resulting in the code inside the if always being executed.
I've made the necessary fixes in the code below, which you can just run from here. As you can see, you were almost there. I just needed to make those two small fixes. :)
var randomNumberA = Math.round((Math.random() * 50) +1)
var randomNumberB = Math.round((Math.random() * 50) +1)
document.write('He runs at ' + randomNumberA + 'm/s which took him ' + randomNumberB + 's. How far did he run?');
var distance = randomNumberA * randomNumberB
function Submit()
{
var answer = document.getElementById('inputAnswer')
if(distance == parseFloat(answer.value)){
alert("Congrats! You got it right!");
} else{
alert("Try again!");
location.reload();
}
}
<body>
<input type='text' id='inputAnswer'/>
<input type='button' onClick='Submit()' value='Submit'/>
</body>
Not completely sure that I understand your question. But, here's some info that will hopefully help:
if(distance == true){
This will render true if there's a value, unless the value is set to false. It's like saying:
if (distance)
If you want to test to see if the value matches the formula, you would just do something like this:
function Submit()
{
var answer = document.getElementById('inputAnswer').value // not 'answer'
if(distance === answer){
alert("Congrats! You got it right!");
} else{
alert("Try again!");
location.reload();
}
}
Hope that helps
you could also get the value via JQuery if your'e using that. It would be the following:
var answer = $('#inputAnswer').val();
Cheers!

Categories