Cannot set property innerHTML of null on appended child (div) - javascript

Before I learn some Unity I wanted to be able to create a simple Javascript game out of my own knowledge. So, I started experimenting with a timer and it worked. Then I wanted to add a div element to my HTML document and have its text change in response to the timer. So I wrote this code:
var counter = 0;
var seconds = 0;
$(document).ready(function(e) {
var element = document.createElement("div");
element.id = "text2";
document.getElementById("canvas").appendChild(element);
function gameActions() {
document.getElementById("canvas").innerHTML = seconds;
if (seconds == 1) document.getElementById("text2").innerHTML = "second";
else document.getElementById("text2").innerHTML = "seconds";
counter++;
if (counter % 50 == 0) {
seconds++;
}
}
setInterval(gameActions, 20);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvas" class="imgcenter" style="width: 500px; height: 400px; background-color: #eeffee;">
</div>
Basically I'm intending to change the text of the "parent" div which displays the number of seconds passed after the html page is fully loaded. But before that, I'm trying to create a div with id text2 to add it inside the div parent.This div should display the word "seconds" depending on the time (basically display "second" when the seconds variable is 1, and "seconds" when not)
Where "imgcenter" is only CSS to specify auto margin. The error is that, whenever I run this on Chrome, I get:
Uncaught TypeError: Cannot set property 'innerHTML' of null
Am I correct to assume the div is not being added? Am I missing a step in the addition? Please let me know what you think the error is, thank you

This code:
var element = document.createElement("div");
element.id = "text2";
document.getElementById("canvas").appendChild(element);
… puts the element you are trying to target inside the canvas div.
This code:
document.getElementById("canvas").innerHTML = seconds;
… destroys everything in that element and replaces it with the HTML in the seconds variable.
Am I correct to assume the div is not being added?
No. The div is added, but then you destroy it before trying to do anything with it.

In your line document.getElementById("canvas").innerHTML = seconds; you are replacing your complete innterHTML of canvas. By that your element text2 is removed again.
If you want to show the unit independently from the seconds in it's own element, you should create an element unitfor example like this:
var counter = 0;
var seconds = 0;
$(document).ready(function (e) {
var element = document.createElement("div");
var unit = document.createElement("div"); // create a second element unit
element.id = "text2";
unit.id = "unit"; // asign the id unit
document.getElementById("canvas").appendChild(element);
document.getElementById("canvas").appendChild(unit);
function gameActions() {
document.getElementById("unit").innerHTML = seconds; // replace the unit with the valuen of seconds
if (seconds == 1) document.getElementById("text2").innerHTML = "second";
else document.getElementById("text2").innerHTML = "seconds";
counter++;
if(counter % 50 == 0) {
seconds++;
}
}
setInterval(gameActions, 20);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvas" class="imgcenter" style="width: 500px; height: 400px; background-color: #eeffee;">
</div>

You are removing the element you added when you replace the inner HTML of the canvas. It would be better if you just updated the entire contents with the entire string instead of creating a separate element. I would also wrap it in an IIFE so that the variables don't leak into the global scope.
(function () {
var counter = 0;
var seconds = 0;
var canvas = document.getElementById("canvas");
function gameActions() {
canvas.innerHTML = seconds + " second" + (seconds > 1 ? "s" : "");
counter++;
if (counter % 50 == 0) {
seconds++;
}
}
$(function() {
setInterval(gameActions, 20);
});
})();
http://jsfiddle.net/1unn153b/

Related

How to make clearInterval() work in JavaScript

I want to make an element (id=runner) move across the page by n pixels after a mouseover event, then stop at a certain position (left = 2000px), using setInterval() to repeatedly call move_left(), then clearInterval() when left == 200px. I can make the element move, but when I look in developer tools it never stops - left continues to increase. I am pretty new to JavaScript/HTML/CSS. How do I make it stop?
Relevant code:
<script>
function runner_go()
{
var load_time = performance.now();
const go = setInterval(move_left,20);
}
function move_left()
{
document.getElementById('runner').style.visibility = "visible";
var runner_position = getComputedStyle(document.getElementById('runner')).getPropertyValue('left');
document.getElementById('runner').style.left = parseInt(runner_position,10) + 17 + "px";
if (parseInt(runner_position,10) > 2000)
{
clearInterval(go);
}
}
</script>
</head>
<body style="background-color:gray;" onmouseover = "runner_go();">
<div>
<h1>Running!</h1>
</div>
<img src="images/runner_l.png" alt ="running man" style="position:relative; visibility:hidden;" id = "runner"/>
</body>
You need to create the var 'go' outside the method cause of the scope, also if you let on the 'body' the 'onmouseover' it will set the interval everytime.
Try this code to test:
<head>
<script>
let go = null;
function runner_go()
{
var load_time = performance.now();
go = setInterval(move_left,20);
}
function move_left()
{
document.getElementById('runner').style.visibility = "visible";
var runner_position = getComputedStyle(document.getElementById('runner')).getPropertyValue('left');
document.getElementById('runner').style.left = parseInt(runner_position,10) + 17 + "px";
if (parseInt(runner_position,10) > 2000)
{
clearInterval(go);
}
}
</script>
</head>
<body style="background-color:gray;" onclick = "runner_go();">
<div>
<h1>Running!</h1>
</div>
<img src="images/runner_l.png" alt ="running man" style="position:relative; visibility:hidden;" id = "runner"/> </body>
Problem -
You declared the interval variable as a constant within another function which is not accessible by the move_left function
So just move your interval variable to global scope (outside the function) and it should work
let go;
function runner_go() {
var load_time = performance.now();
go = setInterval(move_left, 20);
}
function move_left() {
document.getElementById('runner').style.visibility = "visible";
var runner_position = getComputedStyle(document.getElementById('runner')).getPropertyValue('left');
document.getElementById('runner').style.left = parseInt(runner_position, 10) + 17 + "px";
if (parseInt(runner_position, 10) > 2000) {
clearInterval(go);
}
}
sample on how intervals and clearIntervals work
let interval, i = 1;
function start() {
interval = setInterval(log, 1000);
}
function log() {
if (i >= 5) clearInterval(interval);
console.log(`Test ${i}`);
i++
}
start();

How so I make the background of the page red, after the counter reaches zero?

This is my code and it runs, but I have to change the background color to red when the counter reaches zero.
<script>
window.onload = function () {
const tag = document.getElementById("tag1");
var time = 100;
const getTime = ()=>{
time = time - 1;
tag.innerHTML = "Goodbye Aliens: ship leaves in " + time + " secs ";
}
setInterval(getTime, 500);
}
</script>
<body>
<div>
<h1 id="tag1">Hello Earthling</h1>
</div>
</body>
<script>
const tag = document.getElementById("tag1");
tag.innerHTML = "Goodbye Aliens";
</script>
</html>
I thought of something like this in order to do it:
function changeColor() {
if (time == 0) {
document.change.bgColor = "red";
}
}
but it does not work and I do not understand where to put the code in the first place.
Please explain if someone has time. Thanks
My approach would be to check the time variable inside the GetTime method and calling changeColor when its 0.
Then you need to clear the interval using clearInterval to stop the loop.
function changeColor() {
document.querySelector("body").style.backgroundColor = "red";
}
window.onload = function () {
const tag = document.getElementById("tag1");
var time = 10;
const getTime = () =>{
time = time - 1;
tag.innerHTML = "Goodbye Aliens: ship leaves in " + time + " secs ";
if(time === 0){
changeColor();
window.clearInterval(interval);
}
}
var interval = setInterval(getTime, 500);
}
const tag = document.getElementById("tag1");
tag.innerHTML = "Goodbye Aliens";
<div>
<h1 id="tag1">Hello Earthling</h1>
</div>
I tend to favour setTimeout over setInterval. It seems more managable.
Note: I've used a class here instead of directly setting the style on the element.
const tag = document.getElementById('tag1');
// `getTime` accepts a time argument which
// we initialise as 100
function getTime(time = 100) {
// Print the message using `textContent` rather than `innerHTML`
tag.textContent = `Goodbye Aliens: ship leaves in ${time} secs`;
// If time reaches 0 set the background to red using a class
if (time === 0) {
tag.classList.add('red');
// Otherwise call `getTime` again passing in a decremented
// `time` value as the argument
} else {
setTimeout(getTime, 50, --time);
}
}
// Call `getTime` after showing the initial message
setTimeout(getTime, 2000);
.red { background-color: red; }
<div>
<h3 id="tag1">Hello Earthling</h3>
</div>

Countdown timer counting too far

I am trying to make a game that tests how many times you can click on a div in a minute. I can not get my countdown to function properly. My countdown should stop at 0, but instead it keeps going after reaching 0. My code is below. Any ideas?
let div = document.getElementById("div");
let score = document.querySelector("h3");
let time = document.querySelector("span");
var jsTime = 60;
var jsScore = 0;
alert("Click inside the box as many times as you can in one minute. \n Ready?");
var clicker = div.addEventListener("click", function() {
jsScore++;
score.innerHTML = jsScore;
}, 1);
var i = 60;
setInterval(function() {
if (i > 1) {
jsTime--;
time.innerHTML = jsTime;
} else {
removeEventListener(clicker);
}
}, 1000);
#div {
text-align: center;
width: 100px;
height: 100px;
background: black;
color: white;
}
#container {
display: inline-block;
}
<h1>Click inside the box as many times as you can in one minute.</h1>
<br>
<div id="container">
<h2>Time:</h2><span>60</span>
<h2>Score:</h2>
<h3>0</h3>
</div>
<div id="div"></div>
You're decreasing the jsTime as long as i is > 1, which it will always be, since you never decrease the value of i. I think you meant to use jsTime in the conditional instead. Renaming it to something that gives it some context may make it easier to follow. Ex remainingTimeSeconds. See the revised code below.
let div = document.getElementById("div");
let score = document.querySelector("h3");
let time = document.querySelector("span");
var jsTime = 60;
var jsScore = 0;
alert("Click inside the box as many times as you can in one minute. \n Ready?");
var clicker = div.addEventListener("click", function() {
jsScore++;
score.innerHTML = jsScore;
},1);
setInterval(function() {
// As long as there is time left, keep decreasing it, and update the time element's innerHTML with the new current time.
if (jsTime > 1){
jsTime--;
time.innerHTML = jsTime;
} else {
removeEventListener(clicker);
}
},1000);

Loading/Buffering text while loading audio in html5 custom player with JavaScript

I found a custom html5 audio player and successfully redesigned it, now I want to add a "loading/buffering" text while player is loading audio (otherwise users may freak out because nothing happening after they hit play).
Here is the code to explain:
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60),
seconds_int = length - minutes * 60,
seconds_str = seconds_int.toString(),
seconds = seconds_str.substr(0, 2),
time = minutes + ':' + seconds
return time;
}
function calculateCurrentValue(currentTime) {
var current_hour = parseInt(currentTime / 3600) % 24,
current_minute = parseInt(currentTime / 60) % 60,
current_seconds_long = currentTime % 60,
current_seconds = current_seconds_long.toFixed(),
current_time = (current_minute < 10 ? "0" + current_minute : current_minute) + ":" + (current_seconds < 10 ? "0" + current_seconds : current_seconds);
return current_time;
}
function initProgressBar() {
var player = document.getElementById('player');
var length = player.duration
var current_time = player.currentTime;
// calculate total length of value
var totalLength = calculateTotalValue(length)
jQuery(".end-time").html(totalLength);
// calculate current value time
var currentTime = calculateCurrentValue(current_time);
jQuery(".start-time").html(currentTime);
var progressbar = document.getElementById('seekObj');
progressbar.value = (player.currentTime / player.duration);
progressbar.addEventListener("click", seek);
if (player.currentTime == player.duration) {
$('#play-btn').removeClass('pause');
}
function seek(evt) {
var percent = evt.offsetX / this.offsetWidth;
player.currentTime = percent * player.duration;
progressbar.value = percent / 100;
}
};
function initPlayers(num) {
// pass num in if there are multiple audio players e.g 'player' + i
for (var i = 0; i < num; i++) {
(function() {
// Variables
// ----------------------------------------------------------
// audio embed object
var playerContainer = document.getElementById('player-container'),
player = document.getElementById('player'),
isPlaying = false,
playBtn = document.getElementById('play-btn');
// Controls Listeners
// ----------------------------------------------------------
if (playBtn != null) {
playBtn.addEventListener('click', function() {
togglePlay()
});
}
// Controls & Sounds Methods
// ----------------------------------------------------------
function togglePlay() {
if (player.paused === false) {
player.pause();
isPlaying = false;
$('#play-btn').removeClass('pause');
} else {
player.play();
$('#play-btn').addClass('pause');
isPlaying = true;
}
}
}());
}
}
initPlayers(jQuery('#player-container').length);
Player code (source) on CodePen
I want some text will be shown in the same "span" that shows
"start time" (please see CodePen) while media is loading;
The text " 'loading.' 'loading..' 'loading...' " must changing on
loop while media is loading;
When it is loaded the "loading" text must be changing on "start
time" as it is now.
So basically I wat to put some text in start time while it is not shows anything but zeroes
I'm new to JS
Thats why I need some help or point to right direction
You can use the "readyState" event of the audio player to show hide loading.
There is already a "SetInterval" even which is getting fired so in that we can add this code to show/hide the "Loading"
1st add the loading element(You can put it where ever you want"
<h3 id="loading" style="display:none;">Loading</h3>
Now let's add the code to check "readystate" inside "SetInterval"
if(player.readyState>0&&player.readyState<4){
$("#loading").show();
}
else{
$("#loading").hide();
}
You can read more about "readystate" here
/As per the request I have changed the code to use the start time as loading, to make it work we don't have to add anything inside html but need to do some changes in JS
First, add this inside "togglePlay" functions pay condition in the "else" block.
$(".start-time").html("Loading...");
After this inside "initProgressBar()" function replace the "jQuery(".start-time").html(currentTime);" with the below code
if (player.readyState === 4) {
jQuery(".start-time").html(currentTime);
}
so how it will work, When you click play button the start time text will show as "Loading" but once the file is loaded and the player is ready to play the text will be changed to "start time", Hope it works. Also updated the CodePen for better understanding
You can find the full code in the CodePen
You could use setInterval to cycle through the different 'loading' text and clearInterval when the player's play promise is done.
Here's a basic example:
var dots = 1;
var loading = setInterval(function(){
dots = (dots % 3) + 1;
$(".start-time").text("Loading" + Array(dots + 1).join("."));
console.log($(".start-time").text());
}, 250);
player.play().then(function() {
clearInterval(loading);
}).catch((error) => {
$(".start-time").text("Error loading");
});

Creating a counter

I'm creating a counter and I'm having a hard time making it.
The goal of the counter is that for ever second passed a number will increase by 170.
As you can see below the number does not add up and is made on a new line, mostly because I dont know how to make it add up. Some thing like this clock from The Economist
<!DOCTYPE html>
<html>
<body>
<p>Click the button see how much AirHelps market increases by every second.</p>
<button onclick="counterFunction()">See it now</button>
<p id="counter"></p>
<script>
function counterFunction() {
setTimeout(function () {
var text = "";
var i = 170;
while (i < 3500) {
text += "<br>The number is " + i;
i+=170;
}, 1000) }
document.getElementById("counter").innerHTML = text;
}
</script>
</body>
</html>
Any ideas on how I can make this and what is wrong with my code?
Don't use inline JavaScript (JavaScript inside HTML element attributes), it is horrible for maintainability and readability.
You seem to have a misconception about how timeouts, intervals and while loops work, what you want is an interval.
Define a count variable outside of the event listener function, then on each iteration of the interval increment the count variable by one and multiply that number by 170.
I added a little bit in there to hide the button once it has been clicked, just to stop the user from restarting the counter.
var clicker = document.getElementById('clicker');
var counter = document.getElementById('counter');
var count = 0;
clicker.onclick = function() {
setInterval(function () {
counter.textContent = "The number is " + ++count * 170;
}, 1000);
clicker.style.display = 'none';
}
<p>Click the button see how much AirHelps market increases by every second.</p>
<button id="clicker">See it now</button>
<p id="counter"></p>
http://jsfiddle.net/mblenton/Le4vxzrn/2/
function counterFunction() {
var text = ""; var i = 170; var delay = 0; var k = 1;
while (i < 3500) {
text = "The number is " + i;
i += 170;
delay = k * 1000;
doSetTimeout(text, delay);
k++;
}
}
function doSetTimeout(text, delay) {
setTimeout(function () {
document.getElementById("counter").textContent = text;
}, delay);
}
You need to use setInterval, not setTimeout`. Note that if you click the button, it will reset your timer.
You also need to declare var i and var text outside the scope of the Interval, or they will also be reset each iteration.
There were a few things wrong with your code. Among other things:
your i variable was declared in the wrong place to be reused
your closing braces were in the wrong place for the callback function
you were using a while loop, which runs synchronously, whereas you really want to just use a setInterval call.
This should work:
function counterFunction() {
var i = 170;
var text = "";
var interval = setInterval(function () {
text += "<br>The number is " + i;
i+=170;
document.getElementById("counter").innerHTML = text;
if (i >= 3500) {
clearInterval(interval);
}
}, 1000);
}
<p>Click the button see how much AirHelps market increases by every second.</p>
<button onclick="counterFunction()">See it now</button>
<p id="counter"></p>
Ok so the adder variable should be declared outside of the timeout function, because if not you are replacing the value. and you should use setInterval
var p =0;
function counterFunction(){
setInterval(function(){ p+=170;
console.log('value of p '+p);
}, 3000);
}
if you dont want to roll your own here is a nice counter
http://keith-wood.name/countdown.html

Categories