68

I get the a "ReferenceError: document is not defined" while trying to

var body = document.getElementsByTagName("body")[0];

I have seen this before in others code and didn't cause any trouble. Why is it now? The companied HTML page is just a div inside the body.

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" type="text/css" href="css/quiz.css" />
    <script type="text/javascript" src="js/quiz.js"></script>
</head>
<body>

    <div id="divid">Next</div>

</body>
</html>

the code is the following:

(function(){
        var body = document.getElementsByTagName("body")[0];

        function Question(question, choices, correctAns) {
            this.question = question;
            this.choices = choices;
            this.correctAns = correctAns;
        }

        Question.prototype.checkAns = function(givenAns){
            if (this.correctAns === givenAns) {
                console.log("OK");
            }
        };

        function Quiz() {
            this.questions = [];
        }

        Quiz.prototype.showAllQuestions = function(){
            this.questions.forEach(function(questions){
                console.log(questions.question);
            });
        };

        Quiz.prototype.showQuiz = function(){
            this.questions.forEach(function(questions){

                for (var i=0; i < questions.choices.length; i+=1) {
                    body.innerHTML(
                            "<input type=\"radio\" name=\"sex\" value=\"male\">" 
                            + questions.choices[i] + "<br>");
                }

            });
        };

        var q1 = new Question("What is red?", ["Color","Animal","Building"],1);
        var q2 = new Question("Most popular music?", ["Latin","Pop","Rock"],2);
        var quiz = new Quiz();

        quiz.questions.push(q1);
        quiz.questions.push(q2);
        quiz.showAllQuestions();


        })();

Try the whole code in this link HERE

limitcracker
  • 2,208
  • 3
  • 24
  • 23

12 Answers12

61

This happened with me because I was using Next JS which has server side rendering. When you are using server side rendering there is no browser. Hence, there will not be any variable window or document. Hence this error shows up.

Work around :

If you are using Next JS you can use the dynamic rendering to prevent server side rendering for the component.

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(() => import('../components/List'), {
  ssr: false
})

export default () => <DynamicComponentWithNoSSR />

If you are using any other server side rendering library. Then add the code that you want to run at the client side in componentDidMount. If you are using React Hooks then use useEffects in the place of componentsDidMount.

import React, {useState, useEffects} from 'react';

const DynamicComponentWithNoSSR = <>Some JSX</>

export default function App(){

[a,setA] = useState();
useEffect(() => {
    setA(<DynamicComponentWithNoSSR/>)
  });


return (<>{a}<>)
}

References :

  1. https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr
  2. https://reactjs.org/docs/hooks-effect.html
Trect
  • 2,759
  • 2
  • 30
  • 35
9

It depends on when the self executing anonymous function is running. It is possible that it is running before window.document is defined.

In that case, try adding a listener:

window.addEventListener('load', yourFunction, false);
// OR: 
window.addEventListener('DOMContentLoaded', yourFunction, false);
    
yourFunction () {
  // some code
}

Update: (after the update of the question and inclusion of the code)

Read the following about the issues in referencing DOM elements from a JavaScript inserted and run in head element:

danik0011
  • 72
  • 10
erosman
  • 7,094
  • 7
  • 27
  • 46
6

You may deactivate ssr for the whole component (check Trect's answer), but it's overkill since you only need to skip one line in ssr.

You should only check if document is defined (determining if the function is called server-side -no document- or client-side -document defined-):

if (typeof document === 'undefined') {
    // during server evaluation
} else {
    // during client's browser evaluation
}

In your case, you don't need to do anything server-side, you may do something like:

var body = null;

if (typeof document !== 'undefined') {
    // will run in client's browser only
    body = document.getElementsByTagName("body")[0];
}
Vincent J
  • 4,968
  • 4
  • 40
  • 50
5

Try adding the script element just before the /body tag like that

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" type="text/css" href="css/quiz.css" />
</head>
<body>

    <div id="divid">Next</div>
    <script type="text/javascript" src="js/quiz.js"></script>
</body>
</html>
1

Adding "defer" attribute to <script> tag can also fix it.

<script defer src="yourScript.js"></script>   

In this case you can keep <script> inside of <head>.

1

This happened mostly to front-end developers using javascript and trying to execute their code with node. I know you must have tried to use node or any other run-time environs to execute your code. but sadly, in Node, the document object or window object does not exist, instead, we have modules. this means if your script contains Document.getElement, or you try to operate on your DOM, you are gonna get this error. Same with the window object,e.g Window.alert("Hi") , and The import e.g import as File from "./MyFile", you will definitely get an error while trying to execute your code with node because Node is a Server-Side Javascript Run-Time Environment. In same sense, we have the global objects, if you must have heard of it like (console,this) are all global variables.

0

This issue happened when you call the eliment which didn't created yet You called the body and it's component in <head > Call the file in the end of< body > Just before </body> will solve it.

0

If you want to access the HTML DOM Document Object directly in Typescript, this implies that you will use the browser as the environment and have the Type Script tooling generate the code behind, while you use a code editor like VsCode to debug through your typescript.

const document: Document = document as Document;

or if you want to use it into a class just do:

class ExampleClass {
   private document: Document;
   private btn: HTMLElement;

   constructor() {
       this.document = document as Document;
   }

   public exampleOfGettingAButton(): void {
       this.btn = this.document.getElementById("my-btn");
   }
}
David Petric
  • 324
  • 3
  • 17
0

Problem: I got this error while using tailwind components from [tailwind-elements]. (https://tailwind-elements.com/)

Explanation: The error is caused because NextJs renders the page in the server only and in the server document (document is used inside tailwind-elements)is not available.

Solution: Use a dynamic route from NextJS.

import dynamic from "next/dynamic";

const {} = dynamic(import("tw-elements"), { ssr: false });
Chetan B B
  • 31
  • 1
0

Javascript loads before the DOM content, that’s why you get undefined. You could try to add the attribute ‘defer’ to the script tag:

<script src="./index.js" defer></script>

Josie Koay
  • 735
  • 7
  • 8
0

Just check javascript file is in the folder or not. For Example:

My 'javascript' file and my 'html' file are in the same folder. So I don't need to type a subfolder path. I can write just : "first.js"

<body>
    <script src="first.js"></script>
</body>

But İf your 'javascript' and your 'html' file are in different folders.You have to use subfolder path. For example:

<body>
    <script src="js/first.js"></script>
</body>

I hope this information is useful to you.I was getting this error because I'm not paying attention to it.

Hoşçakalın :)

-9

try: window.document......

var body = window.document.getElementsByTagName("body")[0];
CodeZi.pro
  • 229
  • 5
  • 8