Encountering a ReferenceError while attempting to implement logic on a newly created page

I've been experimenting with building a website using the Fresh framework. My goal was to add a simple drop-down feature for a button within a navigation bar, but I'm struggling to figure out where to place the necessary code. I attempted creating a class inside the index.tsx file and initializing it within the export default function Home(), however, all I encountered was a ReferenceError due to document not being defined.

index.tsx

/** @jsx h */
import { h } from "preact";
import HeaderWithLogin from "../islands/HeaderWithLogin.tsx";
import Navbar from "../islands/Navbar.tsx";

class Dropdown {
    private _targetElement: Element | null;
    private _triggerElement: Element | null;
    private _visible: boolean;

    constructor(
        targetElement: Element | null = null,
        triggerElement: Element | null = null
    ) {
        this._targetElement = targetElement;
        this._triggerElement = triggerElement;
        this._visible = false;
        this._init();
    }

    _init() {
        if (this._triggerElement) {
            this._triggerElement.addEventListener("click", () => {
                this.toggle();
            });
        }
    }

    _handleClickOutside(ev: MouseEvent) {
        const clickedE = ev.target as Element;
        if (
            clickedE !== this._targetElement &&
            !(this._targetElement as Element).contains(clickedE) &&
            !this._triggerElement?.contains(clickedE) &&
            this._visible
        ) {
            this.hide();
        }
        document.body.removeEventListener(
            "click",
            this._handleClickOutside,
            true
        );
    }

    toggle() {
        if (this._visible) {
            this.hide();
            document.body.removeEventListener(
                "click",
                this._handleClickOutside,
                true
            );
        } else {
            this.show();
        }
    }

    show() {
        this._targetElement?.classList.remove("hidden");
        this._targetElement?.classList.add("block");

        document.body.addEventListener("click", this._handleClickOutside, true);

        this._visible = true;
    }

    hide() {
        this._targetElement?.classList.remove("block");
        this._targetElement?.classList.add("hidden");

        this._visible = false;
    }
}

function initDropdown() {
    document
        .querySelectorAll("[data-dropdown-toggle]")
        .forEach((triggerElement) => {
            const targetElement: Element | null = document.getElementById(
                triggerElement.getAttribute("data-dropdown-toggle") as string
            );

            new Dropdown(targetElement, triggerElement);
        });
}

export default function Home() {
    if (document.readyState !== 'loading')  {
        initDropdown();
    }   else    {
        document.addEventListener('DOMContentLoaded', initDropdown);
    }
    return (
        <body>
            <Navbar></Navbar>
        </body>
    );
}

Navbar.tsx

/** @jsx h */
import { h } from "preact";
import { tw } from "@twind";

export default function Navbar()    {
    return (
        <nav>
            <ul>
                <li>
                    <button data-dropdown-toggle="dropdownElement">Dropdown Element</button>
                    <div id="dropdownElement">
                        <ul>
                            <li>
                                <a href="/">Link To Other Page</a>
                            </li>
                        </ul>
                    </div>
                </li>
                <li>
                    <button>Button 1</button>
                </li>
                <li>
                    <a href="/">Button 2</a>
                </li>
                <li>
                    <a href="/">Button 3</a>
                </li>
            </ul>
            <div>
                <input type="text" id="search-navbar" class={tw`block p-2 pl-10 w-full text-gray-900 bg-gray-50 rounded-lg border border-gray-300 sm:text-sm focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500`} placeholder="Search..."></input>
            </div>
        </nav>
    );
}

Error given:

An error occured during route handling or page rendering.

ReferenceError: document is not defined
    at Object.Home (file:///.../routes/index.tsx:89:5)
    at h (https://esm.sh/v87/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d8a8aabdb9bbacf5aabdb6bcbdaaf5acb7f5abacaab1b6bf98edf6eaf6e8">[email protected]</a>/X-ZC9wcmVhY3RAMTAuOC4y/deno/preact-render-to-string.js:4:1003)
    at h (https://esm.sh/v87/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aadad8cfcbc9de87d8cfc4cecfd887dec587d9ded8c3c4cdea9f8498849a">[email protected]</a>/X-ZC9wcmVhY3RAMTAuOC4y/deno/preact-render-to-string.js:4:1103)
    at h (https://esm.sh/v87/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="324240575351461f40575c5657401f465d1f4146405b5c5572071c001c02">[email protected]</a>/X-ZC9wcmVhY3RAMTAuOC4y/deno/preact-render-to-string.js:4:1103)
    at h (https://esm.sh/v87/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="acdcdec9cdcfd881dec9c2c8c9de81d8c381dfd8dec5c2cbec99829e829c">[email protected]</a>/X-ZC9wcmVhY3RAMTAuOC4y/deno/preact-render-to-string.js:4:1103)
    at h (https://esm.sh/v87/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="572725323634237a2532393332257a23387a2423253e3930176279657967">[email protected]</a>/X-ZC9wcmVhY3RAMTAuOC4y/deno/preact-render-to-string.js:4:1103)
    at m (https://esm.sh/v87/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4d3d3f282c2e39603f282329283f603922603e393f24232a0d78637f637d">[email protected]</a>/X-ZC9wcmVhY3RAMTAuOC4y/deno/preact-render-to-string.js:3:684)
    at render (https://deno.land/x/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8aecf8eff9e2cabba4baa4bb">[email protected]</a>/src/server/render.tsx:180:16)
    at Object.render [as renderFn] (file:///.../main.ts:20:3)
    at render (https://deno.land/x/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9afce8ffe9f2daabb4aab4ab">[email protected]</a>/src/server/render.tsx:184:14)

To resolve this error, I believe that including the required code in a script tag would suffice. However, I'm also interested in exploring alternative methods of incorporating code into pages. Is there a more efficient way to do so, or is the script tag the most optimal solution?

Answer №1

document is a global object specific to browsers and is not available in other environments.

It is important to check if document is defined instead of assuming its presence.

if (typeof document !== 'undefined') {
  // use document
}

Instead of relying on browser globals like document, it is recommended to utilize refs with container elements when working with UI frameworks such as Preact.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Setting the sidebar width for Nebular with two sidebars in the layout: A step-by-step guide

Having two sidebars (identified as left and right) in my page layout, I initially set both sidebars to a width of 400px using the custom theme method with sidebar-width: 400px. However, I now need to change the width of the right sidebar to 700px. Is the ...

Changing images in vuejs

I am seeking to achieve a seamless transition between two images along with a corresponding legend. These images are sourced from an object-array collection. Since transitions operate only on single tags and components, I have devised a component to encap ...

How can I use a JavaScript function to remove an element from a PHP array?

Imagine I have a PHP session array: $_SESSION[MyItems]=Array('A'=>"Apple", 'B'=>"Brownie", 'C'="Coin")) which is utilized to showcase items on a user's visited page. I want the user to have the ability to remove o ...

Tips for incorporating external functions into Vue Component data synchronization:

As someone new to JavaScript, I am trying to incorporate external functions into Vue component data bindings, but I am encountering issues. helper.js function groupArrayOfObjects(list, key) { return blah blah } function parseDate(d) { ret ...

Transferring information from JSON to HTML

Recently, I came across this handy design tool within our service that helps generate Gauge charts by simply adding a specific div class to the desired pages. <div class="gauge" id="g0" data-settings=' { "value": ...

The React Native blob or file seems to be encountering trouble in reaching the server

I'm in a tough spot here. I can't figure out what's going wrong. My goal is to send a file using the expo-image-picker component to the server. The form gets sent, but the image doesn't. When I use the fetch command, I immediately get a ...

Locating the Searchbox on Google Maps with the angular-google-maps library

I am currently working on positioning the Google Maps searchbox variable in a way that allows it to stay fixed under markers as they are listed. I am utilizing the Angular Google Maps library for this purpose, which provides a directive known as <ui-g ...

Implementing ID-based filtering for an array of objects with React

Struggling with filtering an object in an array of objects by its ID using React. Here's the scenario: The app is a Notes app that stores each note with its Title, Text, and created date, utilizing the ID as the key. Currently, I'm working on c ...

Unit testing in Angular JS is crucial, especially when testing functions in services that do not return any values

Apologies if this has been asked before, but I couldn't find a solution to my issue. I need to create tests for a service within an Angular JS application. The main function of the service returns and is used as an external method. There are also a ...

Navigate to a different subdomain and place a cookie on the newly redirected subdomain

The version of Express is 4.x NodeJS is running on version 12.x At a.example.com, I have a listener for the GET method that redirects to b.example.com and sets a cookie on b.example.com. app.get('/foo', (req, res) => { res.cookie(' ...

Is it possible to transform all scripts into a React component? (LuckyOrange)

I am currently working on converting the script for a specific service (http://luckyorange.com/) into a component. The instructions say to place it in index.html within the public folder, but that appears to be insecure. I'm uncertain whether this tas ...

Display information from an array in checkboxes. If the same data appears in another array, the corresponding checkbox in React will be automatically checked

I currently have two arrays. The first array, let's call it arr1, contains multiple objects such as [{"Name":"Mr.X"},{"Name":"Mr.Y"},{"Name":"Mr.Z"}]. The second array, named arr2, holds a few values like [{"Name":"Mr.Z"}]. My goal is to display all ...

Ways to retrieve data beyond the constructor

Here is the code snippet from my component.ts: export class OrganizationsComponent { public organizations; constructor(public access: OrganizationService) { this.access.getOrganizations().subscribe((data => { this.organizations = data; ...

Retrieving Values from Array with AngularJS Keys - A How-To Guide

I need to access a specific value from a key inside an array, like this: $scope.result = [ { "key":"logo_big", "value":"/assets/images/aaa.jpg" }, { "key":"logo_small", "value":"/assets/images/logo94x57Bis.png" }, { ...

Shifting the entire page from left to right and back again

I am in search for a template that moves the page from left to right. If anyone can guide me on how to create this effect or provide a JavaScript example, I would greatly appreciate it. ...

Transform the JSON format received from the API endpoint to make it suitable for use in the component

I'm working on a react-native app that fetches event data from a wordpress endpoint. Below is the JSON I receive from the wordpress API. How can I restructure it to fit into my calendar component? Where should I handle this restructuring in my app? ...

Using jQuery to decrease the size of a div element containing an image

Hello everyone! I have an image inside a div and I am currently moving it down at a specific time using a delay. My question is, how can I make the image shrink as it moves down the screen until it eventually disappears completely at a set location? Curre ...

Tips for displaying the html content saved in the database onto an ejs webpage

This task seems simple, but I'm struggling to solve it. In my Node.js/Express webapp, I have the Quill.js editor installed. It stores my description in MySQL DB like this: <p><strong>This is the quill data. How are we doing dev?</stron ...

Creating a mesmerizing parallax effect for your image: A step-by-step guide

Looking for help to create a parallax effect on an image when hovered over. Does anyone have any advice or resources? Feeling frustrated at the moment. Here is an example link for reference: http://codecanyon.net/item/jquery-moving-perspective/full_scre ...

Touch interaction operates differently than mouse movement

Imagine three neighboring divs, div1, div2, and div3. When I click on div1 and then move my mouse to div2, the mousemove event is triggered with div2 as the target. However, on mobile devices, if I tap on div1 (touchstart) and slide my finger to div2, the ...