lastElementChild returns null - javascript

I'm working on a Javascript assignment that splits the page into two div elements then appends the div on the left with randomly placed images, then I used .cloneNode() to duplicate on the right, minus the last child image.
That part of it works fine, but I am then supposed to add an event handler to the last element of the left div, but when I try to do this the lastElementChild() method returns null even though the div has the expected child nodes. The code is below and I've commented where the problem is. Any help would be appreciated!
<!DOCTYPE html>
<html>
<head>
<style>
img {position: absolute}
div {position: absolute; height: 500px; width: 500px}
#right {border-left: solid black; left: 500px}
</style>
<script>
<!-- everything here works fine -->
function generateFaces(){
var theLeftSide = document.getElementById("left");
var numberFaces = 5;
for (i = 0; i < numberFaces; i++){
var random_x = Math.random()*400;
var random_y = Math.random()*400;
var image = document.createElement("img")
image.src = "smile.png";
image.setAttribute("style","top: " + random_y + "px;" + "left: " + random_x + "px;");
theLeftSide.appendChild(image);
}
var theRightSide = document.getElementById("right");
leftSideImages = theLeftSide.cloneNode(true);
theRightSide.appendChild(leftSideImages);
theRightSide.lastChild.removeChild(theRightSide.lastChild.lastChild);
}
</script>
</head>
<body onload = "generateFaces()">
<h1> Game </h1>
<p> Instructions </p>
<div id = "right"></div>
<div id = "left"> </div>
<script>
<!-- problem script here -->
var temp = document.getElementById("left");
console.log(temp); // displays <div> with its children <img>
var temp2 = temp.lastElementChild;
console.log(temp2); // returns null
</script>
</body>
</html>

The body's onload event will not fire until after the javascript in your 'problem script' runs.
The order of execution here is basically:
h1, p, #left, and #right get appended to the DOM
script #1 runs, logging the empty #left div and the null lastElementChild.
body onload event fires and script #2 runs (the generateFaces() function). At this point, the <img> tags are inserted into the DOM.
The fix is to make sure that script #1 runs after #2:
<body onload="handleLoad()">
and the JS:
function handleLoad() {
generateFaces()
logStuff()
}
function logStuff() {
var temp = document.getElementById("left");
console.log(temp); // displays <div> with its children <img>
var temp2 = temp.lastElementChild;
console.log(temp2); // logs <img>
}
It might appear, in the console, that #left has images in it at the time that script #1 runs. This is just a quirk of the console; the actual logging happens asynchronously, and since the referenced variable changes in the meantime, the value actually logged is different than what it was when console.log() was called.
You can see this behavior by varying a setTimeout duration on the generateFaces() function call:
function generateFaces() {
var theLeftSide = document.getElementById("left");
var numberFaces = 5;
for (i = 0; i < numberFaces; i++) {
var random_x = Math.random() * 400;
var random_y = Math.random() * 400;
var image = document.createElement("img")
image.src = "smile.png";
image.setAttribute("style", "top: " + random_y + "px;" + "left: " + random_x + "px;");
theLeftSide.appendChild(image);
}
var theRightSide = document.getElementById("right");
leftSideImages = theLeftSide.cloneNode(true);
theRightSide.appendChild(leftSideImages);
theRightSide.lastChild.removeChild(theRightSide.lastChild.lastChild);
}
var temp = document.getElementById("left");
console.log(temp); // displays <div> with its children <img>
var temp2 = temp.lastElementChild;
console.log(temp2); // returns null
setTimeout(generateFaces, 250) // play with this value
img {
position: absolute
}
div {
position: absolute;
height: 500px;
width: 500px
}
#right {
border-left: solid black;
left: 500px
}
<h1> Game </h1>
<p> Instructions </p>
<div id="right"></div>
<div id="left"> </div>
Oh, and note that your generateFaces() function currently creates multiple elements in the DOM with the same id. You're gonna want to fix that.

Your generateFaces() function is called when the body is loaded.
but your second script runs when the window is loaded.
So when the second script runs there is no temp.lastElementChild and you get null.
You can slove is like this
<!DOCTYPE html>
<html>
<head>
<style>
img {position: absolute, height: 30px; width: 30px;}
div {position: absolute; height: 500px; width: 500px}
#right {border-left: solid black; left: 500px}
</style>
</head>
<body onload = "generateFaces()">
<h1> Game </h1>
<p> Instructions </p>
<div id = "right"></div>
<div id = "left"> </div>
<script>
function generateFaces()
{
console.log('y');
var theLeftSide = document.getElementById("left");
var numberFaces = 5;
for (i = 0; i < numberFaces; i++){
var random_x = Math.random()*400;
var random_y = Math.random()*400;
var image = document.createElement("img")
image.src = "smile.png";
image.setAttribute("style","top: " + random_y + "px;" + "left: " + random_x + "px;");
theLeftSide.appendChild(image);
}
var theRightSide = document.getElementById("right");
leftSideImages = theLeftSide.cloneNode(true);
theRightSide.appendChild(leftSideImages);
theRightSide.lastChild.removeChild(theRightSide.lastChild.lastChild);
loaded();
}
<script>
function loaded() {
var temp = document.getElementById("left");
console.log(temp);
var temp2 = temp.lastElementChild;
console.log(temp2);
}

Related

Uncaught TypeError: Cannot read property 'lastChild' of null

<!DOCTYPE html>
<html>
<head>
<title>Face Matching Game</title>
<h2>Matching Game</h2>
<p>Click on the EXTRA face on the left side</p>
<style type="text/css">
div { position: absolute; width: 640px; height: 550px; background-color: maroon }
img { position: absolute; width: 100px; height: 100px}
#rightSide { left: 650px; border-left: 2px solid black; }
</style>
<script type="text/javascript">
var NUM_OF_FACES = 0;
var THE_LEFT_SIDE, THE_RIGHT_SIDE;
//Function to generate faces
function generateFaces() {
THE_LEFT_SIDE = document.getElementById("leftSide");
THE_RIGHT_SIDE = document.getElementById("rightSide");
NUM_OF_FACES += 5;
var image;
while(NUM_OF_FACES>0){
image = document.createElement("img");
image.src = "smile.png";
image.style.top = Math.floor(Math.random()* (THE_LEFT_SIDE.offsetHeight - 100)) + "px";
image.style.left = Math.floor(Math.random()* (THE_LEFT_SIDE.offsetWidth - 100)) + "px";
THE_LEFT_SIDE.appendChild(image);
NUM_OF_FACES -= 1;
//console.log(image.style.top, image.style.left )
}
var leftSideImages = THE_LEFT_SIDE.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
THE_RIGHT_SIDE.appendChild(leftSideImages);
}//end generatefaces()
function deleteFaces(argument) {
while(THE_LEFT_SIDE.firstChild){
THE_LEFT_SIDE.removeChild(THE_LEFT_SIDE.firstChild);
}
while(THE_RIGHT_SIDE.firstChild){
THE_RIGHT_SIDE.removeChild(THE_RIGHT_SIDE.firstChild);
}
}//end deleteFaces()
var theBody = document.getElementsByTagName("body")[0];
THE_LEFT_SIDE = document.getElementById("leftSide");
THE_RIGHT_SIDE = document.getElementById("rightSide");
//Event handling
THE_LEFT_SIDE.lastChild.onclick = function goToNextLevel() {
alert("You clicked on correct face.");
deleteFaces();
generatefaces();
};
theBody.onclick = function gameOver() {
alert("Game Over!!");
theBody.onclick = null;
THE_LEFT_SIDE.lastChild.onclick = null;
};
</script>
</head>
<body onload="generateFaces()">
<div id="leftSide"></div>
<div id="rightSide"></div>
</body>
</html>
I am beginner in Javascript and ran into a problem while doing an assignment.
It is Fact Matching game and you have to click the extra face on the left side and game continues until you click somewhere else than extra face on left.
Above is the HTML file and JS code is embedded in it.
I am getting an error as: Uncaught TypeError: Cannot read property 'lastChild' of null at line number 48, which is onclick event handler function on lastChild of THE_LEFT_SIDE div. I don't know how it is coming and what is the problem with my code?
Any leads will be appreciated.
You are trying to access the element with id leftSide before it has been added to the DOM.
If you move your script to the end of the page body, you will no longer see this error, but a different, unrelated one instead:
<!DOCTYPE html>
<html>
<head>
<title>Face Matching Game</title>
<h2>Matching Game</h2>
<p>Click on the EXTRA face on the left side</p>
<style type="text/css">
div { position: absolute; width: 640px; height: 550px; background-color: maroon }
img { position: absolute; width: 100px; height: 100px}
#rightSide { left: 650px; border-left: 2px solid black; }
</style>
</head>
<body onload="generateFaces()">
<div id="leftSide"></div>
<div id="rightSide"></div>
<script type="text/javascript">
var NUM_OF_FACES = 0;
var THE_LEFT_SIDE, THE_RIGHT_SIDE;
//Function to generate faces
function generateFaces() {
THE_LEFT_SIDE = document.getElementById("leftSide");
THE_RIGHT_SIDE = document.getElementById("rightSide");
NUM_OF_FACES += 5;
var image;
while(NUM_OF_FACES>0){
image = document.createElement("img");
image.src = "smile.png";
image.style.top = Math.floor(Math.random()* (THE_LEFT_SIDE.offsetHeight - 100)) + "px";
image.style.left = Math.floor(Math.random()* (THE_LEFT_SIDE.offsetWidth - 100)) + "px";
THE_LEFT_SIDE.appendChild(image);
NUM_OF_FACES -= 1;
//console.log(image.style.top, image.style.left )
}
var leftSideImages = THE_LEFT_SIDE.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
THE_RIGHT_SIDE.appendChild(leftSideImages);
}//end generatefaces()
function deleteFaces(argument) {
while(THE_LEFT_SIDE.firstChild){
THE_LEFT_SIDE.removeChild(THE_LEFT_SIDE.firstChild);
}
while(THE_RIGHT_SIDE.firstChild){
THE_RIGHT_SIDE.removeChild(THE_RIGHT_SIDE.firstChild);
}
}//end deleteFaces()
var theBody = document.getElementsByTagName("body")[0];
THE_LEFT_SIDE = document.getElementById("leftSide");
THE_RIGHT_SIDE = document.getElementById("rightSide");
//Event handling
THE_LEFT_SIDE.lastChild.onclick = function goToNextLevel() {
alert("You clicked on correct face.");
deleteFaces();
generatefaces();
};
theBody.onclick = function gameOver() {
alert("Game Over!!");
theBody.onclick = null;
THE_LEFT_SIDE.lastChild.onclick = null;
};
</script>
</body>
</html>

Unable to declare variable in onload attribute

I was creating a web page, in which an image moves horizontally until the 'stop me' button is pressed.
<html>
<head>
<script>
var count = 0;
function move(){
image = document.getElementsByTagName("img")[0];
count++;
image.style.left = count;
}
</script>
</head>
<body onload = "var temp = setInterval(move,1)">
<img src = "facebook_icon.png" style = "position:absolute; left = 0; top:0;">
<br>
<button onclick = "clearInterval(temp);">Click here to stop the loop.</button>
</body>
</html>
when I remove the var keyword from the onload attribute, the code runs fine.
New code:-
<html>
<head>
<script>
var count = 0;
function move(){
image = document.getElementsByTagName("img")[0];
count++;
image.style.left = count;
}
</script>
</head>
<body onload = "temp = setInterval(move,1)">
<img src = "facebook_icon.png" style = "position:absolute; left = 0; top:0;">
<br>
<button onclick = "clearInterval(temp);">Click here to stop the loop.</button>
</body>
</html>
Why is it so?
It's a scope issue: variables declared in the attribute are not global, example:
<body onload = "var temp = 'hello'; alert(temp);">
<button onclick = "alert(temp);">Click</button>
</body>
In the above example, on page load, an alert will show the message hello. But, when you click the button you get this error Uncaught ReferenceError: temp is not defined. This means that the variable temp is not accessible (not global).
However, assigning a value to an undeclared variable implicitly creates it as a global variable, that's why your second example works fine:
Try this one.
CSS
<style>
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
</style>
HTML
<div id="container">
<img src="images/up.png" id="animate" />
</div>
<br/>
<br/>
<br/>
<button onclick="myStopFunction()">Click here to stop the loop.</button>
Script
<script type="text/javascript">
function myMove() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 1);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function myStopFunction() {
var elem = document.getElementById("animate");
clearInterval(myMove());
}
</script>

Null reference error in document.element [duplicate]

This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 6 years ago.
I am facing error at append child as the object null value error is there infact i have created the object in the top of script with document get element
and i am trying to get the issue resolve as left side is in there in the div need some help try to figure it out. Please as u read
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Game</title>
<style>
imgg{
position: absolute;
}
div{
width: 500px;
height: 500px;
position: absolute;
}
#rightSide { left: 500px;
border-left: 1px solid black }
</style>
<script>
var numberOfFaces =5 ;
var theLeftSide = document.getElementById("leftSide");
function generateFaces(){
for(var i = 1 ; i <= numberOfFaces ; i++)
{
var imgg = document.createElement("img");
imgg.src = "smile.png";
imgg.style.height = "100px";
imgg.style.width = "100px";
imgg.style.top = Math.random() *400 ;
imgg.style.left = Math.random() *400 ;
theLeftSide.appendChild(imgg);
}
}
</script>
</head>
<body onload="generateFaces()">
<h2>Matching Game</h2>
<p>Click on the extra smiling face on the left.</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
</body>
</html>
document.getElementById("leftSide"); will give error if you put your script inside head. The reason being when js will try to parse this line but there is no such DOM present .
You can resolve it by using
window.onload
put the script tag before closing body tag
<body>
// Dom
<script>
// Rest of code
</script>
</body>
Using window.onload
<head>
//Rest of code
<script>
window.onload = function(){
var numberOfFaces =5 ;
var theLeftSide = document.getElementById("leftSide");
function generateFaces(){
for(var i = 1 ; i <= numberOfFaces ; i++)
{
var imgg = document.createElement("img");
imgg.src = "smile.png";
imgg.style.height = "100px";
imgg.style.width = "100px";
imgg.style.top = Math.random() *400 ;
imgg.style.left = Math.random() *400 ;
theLeftSide.appendChild(imgg);
}
}
}
</script>
</head>
Check this JSFIDDLE , script is wrapped in the body
Place your <script> as last-child of <body> as by the time you are accessing the element using DOM-api, element is not in the DOM
Set position to absolute
Add unit as px(pixel) while assigning top and left
var numberOfFaces = 5;
var theLeftSide = document.getElementById("leftSide");
function generateFaces() {
for (var i = 1; i <= numberOfFaces; i++) {
var imgg = document.createElement("img");
imgg.src = "http://i185.photobucket.com/albums/x304/metalife/transmetropolitan-smile.png";
imgg.style.height = "100px";
imgg.style.width = "100px";
imgg.style.position = 'absolute';
imgg.style.top = Math.random() * 400 + 'px';
imgg.style.left = Math.random() * 400 + 'px';
theLeftSide.appendChild(imgg);
}
}
imgg {
position: absolute;
}
div {
width: 500px;
height: 500px;
position: absolute;
}
#rightSide {
left: 500px;
border-left: 1px solid black
}
<body onload="generateFaces()">
<h2>Matching Game</h2>
<p>Click on the extra smiling face on the left.</p>
<div id="leftSide"></div>
<div id="rightSide"></div>

Matching Game. Javascript. DOM lastChild

There is a simple game. The left and right sides are identical, except for one thing: the left side has one extra face. The user needs to find out and click on that extra face (lastChild). It will trigger the function to double the face quantity.
The problem is - all the faces in my game are lastChild. Where is the problem?
Thanks!
<!DOCTYPE <!DOCTYPE html>
<html>
<head>
<title>Matching Game. Part 3.</title>
<style>
img {
position: absolute;
}
div {
position: absolute;
width: 500px;
height: 500px;
}
#rightSide {
left: 500px;
border-left: 1px solid black;
}
</style>
<script>
function generateFaces(){
var numberOfFaces = 5;
//var theLeftSide = document.getElementById("leftSide");
for(var i=0; i < numberOfFaces; i++) {
var smileImage = document.createElement("img");
smileImage.src="http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
var topPosition = Math.floor(Math.random()* 400) + 1;
var leftPosition = Math.floor(Math.random()* 400) + 1;
smileImage.style.top = topPosition + "px";
smileImage.style.left = leftPosition + "px";
leftSide.appendChild(smileImage);
var leftSideImages = leftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
rightSide.appendChild(leftSideImages);
leftSide.lastChild.style.background = "red";
var theBody = document.getElementsByTagName("body")[0];
leftSide.lastChild.onclick = function nextLevel(event) {
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
}
}
}
</script>
</head>
<body onload = "generateFaces()">
<h1>Matching Game</h1>
<p>Click on the extra smiling face on the left.</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
</body>
</html>
You are binding your click event to every element in the loop. You first need to over-ride the previous handler and then re-bind it to the last element.
function generateFaces(){
var numberOfFaces = 5;
var leftSide = document.getElementById("leftSide");
var rightSide = document.getElementById("rightSide");
for(var i=0; i < numberOfFaces; i++) {
var smileImage = document.createElement("img");
smileImage.src="http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
var topPosition = Math.floor(Math.random()* 400) + 1;
var leftPosition = Math.floor(Math.random()* 400) + 1;
smileImage.style.top = topPosition + "px";
smileImage.style.left = leftPosition + "px";
leftSide.appendChild(smileImage);
var leftSideImages = leftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
rightSide.appendChild(leftSideImages);
leftSide.lastChild.style.background = "red";
var theBody = document.getElementsByTagName("body")[0];
}
var pics = document.getElementsByTagName("img");
for(i=0;i<pics.length;i++){
pics[i].onclick = function() {
return false;
}
}
leftSide.lastChild.onclick = function nextLevel(event) {
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
}
}
img {
position: absolute;
}
div {
position: absolute;
width: 500px;
height: 500px;
}
#rightSide {
left: 500px;
border-left: 1px solid black;
}
<body onload = "generateFaces()">
<h1>Matching Game</h1>
<p>Click on the extra smiling face on the left.</p>
<div id="leftSide"></div>
<div id="rightSide"></div>
</body>

using javascript to randomise a image in background

I am trying to randomise a image in a background, I am having problems because there is content already in the div
this is what i got so far
<div class="welcome-inner">
<script type="text/javascript">
<!--
var imlocation = "welcome/";
var currentdate = 0;
var image_number = 0;
function ImageArray (n) {
this.length = n;
for (var i =1; i <= n; i++) {
this[i] = ' '
}
}
image = new ImageArray(3)
image[0] = 'background1.jpg'
image[1] = 'background2.jpg'
image[2] = 'background3.jpg'
var rand = 60/image.length
function randomimage() {
currentdate = new Date()
image_number = currentdate.getSeconds()
image_number = Math.floor(image_number/rand)
return(image[image_number])
}
document.write("<img src='" + imlocation + randomimage()+ "'>");
//-->
</script>
CONTENT
</div>
the div welcome-inner already has styling in the css
.row-welcome {
border-bottom: 0;
width: 100%;
margin: 0 auto;
overflow: auto;
margin-top: -20px;
background-position: 50% 50%;
background-size: cover;
border-bottom: 1px solid #1e346a;
}
welcome-inner did have a background image but I removed the line to try to get this to work
The problem I am having is that the images are showing up but pushing my content down.
how do I adapt this to make it work?
You're going to need to set the background-image style (if you're using jQuery this will be easier). So, instead of creating an tag which goes in the normal document flow, something more like this:
$("#welcome-inner").style("background-image", imlocation + randomimage());
And change "#welcome-inner" to whatever the selector is for the DOM element you want to set the background-image on.
I think your entire approach is incorrect. Try using .sort(), like:
var doc = document;
function E(e){
return doc.getElementById(e);
}
function range(least, greatest){
var r = [];
for(var i=0,n=least; n<=greatest; i++,n++){
r[i] = n;
}
return r;
}
var rng = range(1, 3);
rng.sort(function(){
return Math.round(Math.random())-0.5;
});
for(var i in rng){
var img = new Image();
img.src = 'welcome/background"+rng[i]+".jpg';
// If you add an id called pickAnId to your welcome-inner className div then
E('pickAnId').appendChild(img);
}

Categories

Resources