Javascript || not working properly

I have this JS function, which should check if there is a firstChild on the element, if there isnt a paragraph should be created with the || document.createElement("p"), but i get an error, Cannot read firstChild property of null

EDIT: shouldnt have the "if(element) on the code, i was about ot try something with that, but it was not there when i had the error

function    update(element,content,klass)   {
    var p   =   element.firstChild  ||  document.createElement("p");        
    p.textContent   =   content;
    element.appendChild(p);
    if(klass)   {
    p.className =   klass;
    }
}

complete JS file

var button = document.getElementById("button");
var rainbow = ["red","orange","yellow","green","blue","indigo","violet"];
////    dom references  ////
var $question   =   document.getElementById("question");
var $score  =   document.getElementById("score");
var $feedback   =   document.getElementById("feedback");


function    update(element,content,klass)   {
    var p   =   element.firstChild  ||  document.createElement("p");

    p.textContent   =   content;
    element.appendChild(p);
    if(klass)   {
    p.className =   klass;
    }
}


var score = 0;

var quiz = {
    "name": "Super Hero Name Quiz",
    "description": "How many super heroes can you name",
    "question": "What is the real name of ",
    "questions": [
        {"question" : "Superman", "answer": "Clarke Kent"},
        {"question" : "Batman" , "answer": "Bruce Wayne"},
        {"question" : "Wonder Woman", "answer": "Dianna Prince"}
    ]
}




function play(quiz){
    for(var i= 0,question,answer,max=quiz.questions.length;i<max;i++){
        question = quiz.questions[i].question;
        answer = ask(question);
        check(answer,i);
    }
    gameOver();

}
play(quiz);

function ask(question){
    update($question,quiz.question + question)
    return prompt("Enter your awnser");
}
function check(answer,index){
    if(answer === quiz.questions[index].answer){
        update($feedback,"Correct!","right");
        score++;
    }
    else{
        update($feedback,"Wrong!","wrong");
    }

}


function gameOver(){

        update($question,"Game  Over,   you scored  "   +   score   +   "points");
}

Html file

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="A quiz game for ninjas">
<meta name="author" content="DAZ">
<title>Quiz Ninja</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>
<h1>Quiz Ninja!</h1>
<p>Score:   <strong id="score">0</strong></p>   
</header>
<script src="js/scripts.js"></script>
<section id="question">
    <p>Question:</p>
</section>
<section id="feedback">
    <p>Feedback</p>

</section>
</body>
</html>

Not sure why i get NULL on $question and $feedback

Upvotes: 0

Views: 993

Answers (2)

pfg
pfg

Reputation: 3577

In javascript, null.someFunction does not return undefined and instead throws a TypeError: null is not an object (evaluating 'null.someFunction'). This is because Javascript cannot get properties of nonexistent variables. This is the same with undefined.someFunction.

The || operator returns the first truthy value that it's given, truthy meaning not null or undefined or 0. However, to find their value it must first evaluate them. Because your code tries to get element.firstChild first, it fails because element is null or undefined. The || operator does not get to run if element.firstChild fails.

Instead, you can check if element is defined before using it.

var p;
if(element)
    p   =   element.firstChild  ||  document.createElement("p");
else
    p   =   document.createElement("p");

To condense this down into one line, you can use a ternary operator

var p   =   element ? element.firstChild : false  ||  document.createElement("p");

Now you'll probably have the error where element is not defined at

element.appendChild(p);

This is because you removed the if statement in your edit.

Another thing, the Javascript file is loaded and executed the moment it finds the script tag. That means it can't find your sections because they haven't been loaded yet. To fix this, move the script to the bottom after everything it needs before it loads:

<section id="question">
    <p>Question:</p>
</section>
<section id="feedback">
    <p>Feedback</p>
</section>
<script src="js/scripts.js"></script>

Then, the tags will be loaded and put in the page and the script will be run and find the tags.

Another option to fix this is using Jquery's $(document).ready(function(){})

If you wrap all your code in

$(document).ready(function(){
  // your code
});

Jquery will wait for the page to fully load before running your code.

Upvotes: 1

Matt Spinks
Matt Spinks

Reputation: 6698

Either $question or $feedback is null. Check your markup and make sure that there is an element defined with id='question', and an element defined with id='feedback'.

Also, the logic in your update function seems a little out of order. You are checking whether your element is null or not, but doing that after you access one of the element's properties. This might better serve you:

function update(element,content,klass) {
    if(element) {
        var p = element.firstChild || document.createElement("p");
        element.appendChild(p);
        p.textContent = content;
        if(klass) {
            p.className = klass;
        }
    }
}

Upvotes: 0

Related Questions