Debugging an XP bar - javascript

I've been working awhile on making this code, but I can't seem to make it work like I want it to. I wanted a prompt to come up, ask for how long you've worked on a topic, then give the correct width on the progress bar.
Edit: widthGenerator creates the popup, but I can't seem to have the variable width in widthGenerator() transfer to Move() as Move's width.
Here is my code:
<body class="w3-container">
<div class="w3-progress-container w3-round-xlarge">
<div id="myBar" class="w3-progressbar w3-round-xlarge" style="width:1%"></div>
</div>
<button class="w3-btn" onclick="move()">Click Me</button>
<script>
function widthGenerator() {
var question = prompt("Enter number of hours worked:", "Enter here");
if (isNaN(question) == false) {
var width = (question * 2.33463);
break;
} else if (isNaN(question) == true) {
question = prompt("That is not a number; Enter the number of hours worked:", "Enter here");
break;
};
}
function move() {
var elem = document.getElementById("myBar");
var id = setInterval(frame, 1);
var width = widthGenerator()
function frame() {
if (width >= widthGenerator()) {
clearInterval(id);
} else {
width += 0.1;
elem.style.width = width + '%';
}
}
}
</script>

You need a return statement in your widthGenerator() function:
function widthGenerator() {
var question = prompt("Enter number of hours worked:", "Enter here");
if (!isNaN(Number(question))) {
var width = (question * 2.33463);
} else {
question = prompt("That is not a number; Enter the number of hours worked:", "Enter here");
}
return width;
}
I didn't want to tinker too much with your code but note that it is possible the user will never enter a number based on how widthGenerator() is written.

This code makes sure, that the user is asked for a valid number, till he gives it. It is also a bit cleaner. And I removed the break as it is not a valid syntax, if you are not inside of an switch.
You may want to remove the timeout in your code, as it will be proccesed after asking for width anyway. And clearing imeout from within of it win't do anything. Lastly I removed function frame, reason 1 beeing, that it was created for every call of move(), but secondly and mostly, it is unecesery as you can use an anonymous function for this type of job.
function widthGenerator() {
var question = prompt("Enter number of hours worked:", "Enter here")
while(isNaN(question)){
question = prompt("That is not a number; Enter the number of hours worked:", "Enter here")
// this will make it loop, till the user gives a valid number
}
return (question * 2.33463)
}
function move() {
var elem = document.getElementById("myBar")
var width = widthGenerator()
// You don't really need the timeout, since you can make the if anyway.
var id = setInterval(function(){
// this is anonymous function, it is used if you need to pass a callback to
if (width >= widthGenerator()) {
// Clearing this timeout won't do anything as you allready did cleared it by calling it
clearInterval(id)
} else {
width += 0.1
elem.style.width = width + '%'
}
}, 1)
}
Feel free to ask any questions.

Related

javascript value is not updating after onmousevent

I use 1 span tag at the moment.
<span onmouseover="numberOne()" onclick="imgNumber(); return false" onmouseout="noHoverOne()" class="img1 img" id="new-img"> </span>
The span has a "deafult" image, when the mouse goes on the span, another image will be shown, when the mouse leaves the span, the default image will be shown again.
now the javascript:
function numberOne() {
var random2 = Math.floor((Math.random() * 3) + 1);
var random3 = Math.floor((Math.random() * 3) + 1);
do {
var random = Math.floor((Math.random() * 3) + 1);
} while (random === numberOne.last);
numberOne.last = random;
Random numbers are made here. So every time you leave the span and go on the span, there will be a different image.
if (random == 2) {
document.getElementById('new-img').style = "background-image: url('http://web-stars.nl/molgeld.jpg');";
} else if ((random==random2)==random3) {
document.getElementById('new-img').style = "background-image: url('http://web-stars.nl/vrijstelling.jpg');";
} else {
document.getElementById('new-img').style = "background-image: url('http://web-stars.nl/haspel.jpg');";
}
These are the images that will be shown depending on the number
return random;
}
var value = numberOne();
function imgNumber() {
document.getElementById('demo').innerHTML = value;
}
imgNumber();
This is where I am stuck. Before I even have touched the span tag with my mouse, there is already a random number and when I go with the mouse on the span tag, it shows a different image but not a different number. I want to use this number somehow to create a new level for my game. The game is influenced by the chosen image.
So there is a lot going on and it's pretty messy. So please, I would love to hear any kind of constructive feedback.
[EDIT] I will keep the JSfiddle up to date, but there is an error in the preview, it won't display anything. It's still useful Jsfiddle
use a wrapper function where you can call both imgNumber and numberOne
function mouseHover() {
var value = numberOne()
imgNumber(value)
}
function imgNumber(value) {
document.getElementById('demo').innerHTML = value;
}
<span onmouseover="mouseHover()" onclick="imgNumber(); return false" onmouseout="noHoverOne()" class="img1 img" id="new-img"> </span>
Your code is a bit illogical. It seems you want to randomly assign an image to an element background and get a different element each time. So put the image URLs in an array and randomly grab one, ensuring it's different to the last. This means you can add or reduce the images you want to display just by modifying the images array.
Also put all your data in an object rather than using globals, it's just neater. And give your functions names that tell you what they do.
E.g.
var imageData = {
pix: ['http://web-stars.nl/molgeld.jpg',
'http://web-stars.nl/vrijstelling.jpg',
'http://web-stars.nl/haspel.jpg'
],
random: null
}
function changeImage(el) {
// limit do loop just in case data is bad
// Infinite loops are bad...
var len = imageData.pix.length;
var i = len;
do {
var random = Math.random() * len | 0;
} while (i-- && imageData.random == random)
imageData.random = random;
el.style.backgroundImage = imageData.pix[random];
console.log(random, imageData.pix[random]);
}
function updateImageRef() {
document.getElementById('imageRef').textContent = imageData.random;
}
<div id="imageDiv" onmouseover="changeImage(this)" onclick="updateImageRef()">Image div</div>
<div id="imageRef"><div>

Button to change text back and forth JS

I am trying to make a button that changes temperature to Fahrenheit on click, but if it is clicked again, changes the temperature back to Celsius. If you click the temperature symbol(i.e Celsius) it should change the temperature to Fahrenheit. If the Fahrenheit symbol, it should show the temperature in Celsius again.
The problem is that my current button changed the temperature to Fahrenheit and immediately changes it back to Celsius.
In my research, I found the toggle() jquery function, but it seems that it is now deprecated and, to be honest, I don't really understand how to use it.n
I also found this stackoverflow qustion, but do not know how to apply the answer to my situation: Switch button text back and forth with Bootstrap and jquery
Thanks!
var currentTemp= "cel";
$("#tempUnit").click(function(){
alert("Temperature Changed to Fahrenheit.");
// var currentTemp= cel;
if (currentTemp=== "cel") {
currentTemp = "faren";
var farCalc= (data.main.temp * 1.8) + 32;
$('#temp').html("Temperature:" + Math.round(farCalc) +"");
$('#tempUnit').html("&#8457");
}
if (currentTemp=== "faren"){
alert("Temperature Changed to Celsius");
$('#temp').html("Temperature:" + data.main.temp +"");
$('#tempUnit').html("&#8451");
}
See full code here: https://codepen.io/mso122591/pen/XZZWPR
The problem is that my current button changed the temperature to Fahrenheit and immediately changes it back to Celsius.
This happens because you are setting currentTemp = "faren" in the condition if (currentTemp=== "cel") which return to true for the first time and then you are again using if condition instead you should use else block like this
var currentTemp = "cel";
$("#tempUnit").click(function() {
alert("Temperature Changed to Fahrenheit.");
// var currentTemp= cel;
if (currentTemp === "cel") {
currentTemp = "faren";
var farCalc = (data.main.temp * 1.8) + 32;
$('#temp').html("Temperature:" + Math.round(farCalc) + "");
$('#tempUnit').html("&#8457");
}
else {
currentTemp = "cel";
alert("Temperature Changed to Celsius");
$('#temp').html("Temperature:" + data.main.temp + "");
$('#tempUnit').html("&#8451");
}
P.S Again set currentTemp = "cel"; in else block
First off the codepen looks broken and honestly extremely difficult to read. I gave up before trying. So I'm will answer in a way that describes how I would approach the problem.
First break up your responsibilities into different functions. Then connect those functions together. You will be managing state (in this case which degree your currently on. And finally attaching to the DOM with the results and the event handler for when the user clicks. Each is it's own self contained function.
$(function() {
var TEMP_SYMBOLS = {
celceus: '&#8451',
fahrenheit: '&#8457'
};
var TEMP_CONVERTERS = {
celceus: function(temp) { return temp; },
fahrenheit: function(temp) { return (temp * 1.8) + 32; }
};
var currentTemp = 0;
var currentTempMode = 'celceus';
function fetchTemp() {
// Here is where you fetch the temp from AJAX.
// For demonstration purposes we will simply hard code a value.
currentTemp = 32.4;
}
function renderTemp() {
var symbol = TEMP_SYMBOLS[currentTempMode];
var converter = TEMP_CONVERTERS[currentTempMode];
var value = converter(currentTemp);
$('#temp-output').html('Temperature: ' + value + ' ' + symbol);
}
fetchTemp();
renderTemp();
$('#temp-output').on('click', function() {
currentTempMode = currentTempMode === 'celceus' ? 'fahrenheit' : 'celceus';
renderTemp();
});
});
#temp-output {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="temp-output">Loading…</span>

Creating a class based JS instead of id

So I have created this javascript that animates a certain place using it's ID.
The problem is that there are many of those on the site and meaning this I'd have to duplicate this function a lot of times just to replace the x in getElementById("x").
So here is the code I fully done by myself:
var popcount = 0;
var opanumber = 1;
var poptimeout;
function pop() {
if (popcount < 10) {
popcount++;
if (opanumber == 1) {
document.getElementById("nav1").style.opacity = 0;
opanumber = 0;
poptimeout = setTimeout("pop()", 50);
}
else {
document.getElementById("nav1").style.opacity = 1;
opanumber = 1;
poptimeout = setTimeout("pop()", 50);
}
}
else {
popcount = 0;
document.getElementById("nav1").style.opacity = 1;
}
}
function stoppop() {
clearTimeout(poptimeout);
popcount = 0;
document.getElementById("nav1").style.opacity = 1;
}
I would gladly appreciate any information on how I could solve this situation and also any tutorials about using classes and "this".
Something like this; rather than hard code a value into a function it is better to pass the value in so you can reuse the function on more than one thing. In this case you can now call startPop and stopPop with the name of a CSS class.
var popTimeout;
function setOpacity(className, value) {
Array.prototype.forEach.call(
document.getElementsByClassName(className),
function(el) {
el.style.opacity = value;
}
);
}
function pop(className, popCount, opaNumber) {
if (popCount < 10) { //Must be even number so you end on opacity = 1
setOpacity(className, opaNumber);
popTimeout = setTimeout(function() {
pop(className, popCount++, 1-opaNumber);
}, 50);
}
}
function startPop(className) {
pop(className, 0, 0);
}
function stopPop(className) {
clearTimeout(popTimeout);
setOpacity(className, 1);
}
In case you are wondering about the 1 - opaNumber; this is a simpler way of switching a value between 1 and 0. As 1-1=0 and 1-0=1.
Well you started out with recognizing where you have the problem and that's already a good thing :)
To make your code a bit more compact, and get as many things as possible out of the local scope, you could check the following implementation.
It is in a sense a small demo, where I tried adding as much comments as possible.
I edited a bit more after realizing you rather want to use classnames instead of id's :) As a result, I am now rather using the document.querySelectorAll that gives you a bit more freedom.
Now you can call the startPop function with any valid selector. If you want to pop purely on ID, you can use:
startPop('#elementId');
or if you want to go for classes
startPop('.className');
The example itself also add's another function, nl trigger, that shows how you can start / stop the functions.
I also opted to rather use the setInterval method instead of the setTimeout method. Both callback a function after a certain amount of milliseconds, however setInterval you only have to call once.
As an extra change, stopPop also now uses the document.querySelectorAll so you have the same freedom in calling it as the startPop function.
I added 2 more optional parameters in the startPop function, namely total and callback.
Total indicates the maximum times you wish to "blink" the element(s), and the callback provides you with a way to get notified when the popping is over (eg: to update potential elements that started the popping)
I changed it a bit more to allow you to use it for hovering over an element by using the this syntax for inline javascript
'use strict';
function getElements( className ) {
// if it is a string, assume it's a selector like #id or .className
// if not, assume it's an element
return typeof className === "string" ? document.querySelectorAll( className ) : [className];
}
function startPop(className, total, callback) {
// get the element once, and asign a value
var elements = getElements( className ),
current = 0;
var interval = setInterval(function() {
var opacity = ++current % 2;
// (increase current and set style to the left over part after dividing by 2)
elements.forEach(function(elem) { elem.style.opacity = opacity } );
// check if the current value is larger than the total or 10 as a fallback
if (current > (total || 10)) {
// stops the current interval
stopPop(interval, className);
// notifies that the popping is finished (if you add a callback function)
callback && callback();
}
}, 50);
// return the interval so it can be saved and removed at a later time
return interval;
}
function stopPop(interval, className) {
// clear the interval
clearInterval(interval);
// set the opacity to 1 just to be sure ;)
getElements( className ).forEach(function(elem) {
elem.style.opacity = 1;
});
}
function trigger(eventSource, className, maximum) {
// get the source of the click event ( the clicked button )
var source = eventSource.target;
// in case the attribute is there
if (!source.getAttribute('current-interval')) {
// start it & save the current interval
source.setAttribute('current-interval', startPop(className, maximum, function() {
// completed popping ( set the text correct and remove the interval )
source.removeAttribute('current-interval');
source.innerText = 'Start ' + source.innerText.split(' ')[1];
}));
// change the text of the button
source.innerText = 'Stop ' + source.innerText.split(' ')[1];
} else {
// stop it
stopPop(source.getAttribute('current-interval'), className);
// remove the current interval
source.removeAttribute('current-interval');
// reset the text of the button
source.innerText = 'Start ' + source.innerText.split(' ')[1];
}
}
<div class="nav1">
test navigation
</div>
<div class="nav2">
Second nav
</div>
<div class="nav1">
second test navigation
</div>
<div class="nav2">
Second second nav
</div>
<a id="navigation-element-1"
onmouseover="this.interval = startPop( this )"
onmouseout="stopPop( this.interval, this )">Hover me to blink</a>
<button type="button" onclick="trigger( event, '.nav1', 100)">
Start nav1
</button>
<button type="button" onclick="trigger( event, '.nav2', 100)">
Start nav2
</button>
If you do want to take it back to using IDs, then you will need to think about popTimeout if you run this on more than one element at a time.
function setOpacity(id, value) {
document.getElementById(id).style.opacity = value;
}
function runPop(id) {
function pop(id, popCount, opaNumber) {
if (popCount < 10) { //Must be even number so you end on opacity = 1
setOpacity(id, opaNumber);
popTimeout = setTimeout(function() {
pop(id, popCount++, 1-opaNumber);
}, 50);
}
}
var popTimeout;
pop(id, 0, 0);
return function() {
clearTimeout(popTimeout);
setOpacity(id, 1);
}
}
var killPop = [];
function startPop(id) {
killPop[id] = runPop(id);
}
function stopPop(id) {
killPop[id]();
}

Adding more If statements for a simple javascript game

I'm a newbie teaching myself how to code using a course through udemy.com. I'm in the process of learning Javascript and as a project we're instructed to created a simple Javascript game. Basically you enter a number that you think the computer is thinking. So far when you enter the correct number and click submit, a box will appear that states "Yay! That's exactly how many fingers I'm holding up!" or if it is not correct it will state "Sorry that's not correct, my number was .."
The problem is I can't figure out how to add additional if statements. For example I'm trying to alert a message that states "oops you need to enter a number" when the user clicks the submit button without entering a number or letter in the box. And when they've guessed the correct number of 0, the alert message will state "That's right, I have no fingers up!"
Here is the code that allows me to do the two instructions I listed above correctly:
<p>How many fingers am I holding up?</p>
<input id="answer"/>
<button id="myButton"><strong>Submit</strong></button>
<script type="text/javascript">
document.getElementById("myButton").onclick=function() {
var x=Math.random();
x=6*x;
x=Math.floor(x); //use floor to get whole number
if (x==document.getElementById("answer").value) {
alert("Yay! That's exactly how many fingers I'm holding up!");
} else {
alert("Sorry that's not correct! My number was" + x );
}
}
</script>
What am I doing wrong here?
Thanks in advance!
Here's a revised script, the problem was with the .value property. Please work on your indentation.
Follow this link for full code JS fiddle
document.getElementById("myButton").onclick = function() {
var x = Math.random();
var y = document.getElementById("answer");
x = 6 * x;
x = Math.floor(x); //use floor to get whole number
if (y.value === "") {
alert("Oops, you need to enter a number!");
} else if (x == y.value) {
if (x == 0) {
alert("That's right, I have no fingers up!");
} else {
alert("Yay! That's exactly how many fingers I'm holding up!");
}
} else {
alert("Sorry that's not correct! My number was " + x);
}
}
var x = Math.random();
x = 6*x;
x = Math.floor(x); //use floor to get whole number
var y = document.getElementById("answer").value;
if(y == null){
alert("Please enter a number");
}else{
if (x == y) {
if(x == 0){
alert("Yay! I'm not holding any fingers up!");
}else{
alert("Yay! That's exactly how many fingers I'm holding up!");
}
} else {
alert("Sorry that's not correct! My number was" + x );
}
}

setInterval() not working after clearInterval() in this Javascript code

I have been ripping my hair off a couple of nights now with this problem:
I'm trying to create an expanding div with JavaScript. Here's the part of the HTML file:
<div id="bbc_div" class="bbc_div" style="display:none; height:200px;">
<input type="button" value="Show BBC" id="bbc_button" onclick="onclickBBC('bbc_div')" />
And here's the magical non-working JavaScript file:
var maxHeight = 100;
var curHeight = 1;
var wait = 5;
var timerID = new Array();
function onclickBBC(obj) {
if (document.getElementById(obj).style.display == "none") {
slideDown(obj);
}
else {
document.getElementById(obj).style.display="none"
}
}
function slideDown(obj) {
document.getElementById(obj).style.height="1px";
document.getElementById(obj).style.display="block";
timerID[obj] = setInterval("slideDownExec(\"" + obj + "\")", wait);
return;
}
function slideDownExec(obj) {
if (curHeight <= maxHeight) {
curHeight++;
document.getElementById(obj).style.height=curHeight + "px";
}
else {
endSlide(obj);
}
return;
}
function endSlide(obj) {
clearInterval(timerID[obj]);
return;
}
When I reload the page, div expands once to its right height. But, if I push the button without reloading page again after it has hided again, it doesn't work. display:block; works, but setInterval() isn't starting. So this happens after clearInterval() has executed. Why is clearInterval() killing my setInterval() permanently?
The timer is running, you just need to reset a variable:
function slideDown(obj)
{
document.getElementById(obj).style.height = "1px";
curHeight = 1;
I would use jQuery for this, it's a LOT easier.
You have an issue with curHeight not being set to 1 at the top of slideDown. If this doesn't happen, the if statement at the top of slideDownExec will only work the first time.
Additionally, does JavaScript allow non-integer array indexes?
> a['i'] = 4
4
> a
[]
> a['i']
4
What you're actually doing is adding a property called i to the array object. You might as well use an empty object rather than an array.

Categories

Resources