javascripthtmlnode.jsjsdom

Is there an easier way to call JS functions in Node.js via HTML-buttons?


I'm trying to add a JavaScript function that I wrote myself, to an HTML button which I also did myself. I'm having problems calling the document.getElementById() function because I'm working with Node.js. I read in some other forum, you can work around that with JSDOM. Now I'm having problems with that. Is there any other solution which is easier than the JSDOM-way? I also can't really use JSDOM because it would require a new installation which couldn't be done in the intire team time-wise.

JS code

const fetch = require("./fetch");
const jsdom = require('jsdom');
const http = require('http');
const fs = require('fs');
var url = require('url');
const  port = 3000



const server = http.createServer(function(req, res) {
    
    var q = url.parse(req.url);
    var filename = "." + q.pathname;
    console.log(req.url)

    if (req.url == '/') {
        res.writeHead(301, { Location: 'http://localhost:3000/frontpage.html' })
        res.end()
        } else {
            res.writeHead(200, { 'Content-Type': 'text/html' })
            fs.readFile(filename, function(error, data) {
                if(error) {
                    res.writeHead(404)
                    res.write('Error: File Not Found')
                } else {
                    res.writeHead(200, { 'Content-Type': 'text/html' })
                    res.write(data)
                }
                return res.end()
            })
    }
})

server.listen(port, function(error) {
    if (error) {
        console.log('Something went wrong', error)
    } else {
        console.log('Server is listening on port ' + port)
    }
})






const { JSDOM } = jsdom;

const { document } = (new JSDOM('frontpage.html')).window;
global.document = document;
var button = document.getElementById("meinButton")
button.addEventListener("click", fetch.register_medication);

HTML Elements

    <script scr="fetch.js"></script>
    
    <button id="meinButton">Klick mich!</button>

Solution

  • It looks like you've gotten your serverside code and your clientside code mixed up. NodeJS is for the server; clientside activity such as adding an event handler to a button should be running in the client, not embedded inside a node script. It can be confusing, since both are written in the same language (with different libraries available), and some modern toolchains and libraries kind of conceptually blur the difference between serverside and clientside code -- but they're executed in completely different contexts and can't be intermingled.

    This first part of your code is meant for the node server, and will be executed on the host; it looks like what it's doing is checking the (server's) filesystem for paths that match the url, reading them using fs, and sending the contents on to the browser:

    const server = http.createServer(function(req, res) {
        var q = url.parse(req.url);
        var filename = "." + q.pathname;
        if (req.url == '/') {
            res.writeHead(301, { Location: 'http://localhost:3000/frontpage.html' })
            res.end()
            } else {
                res.writeHead(200, { 'Content-Type': 'text/html' })
                fs.readFile(filename, function(error, data) {
                    if(error) {
                        res.writeHead(404)
                        res.write('Error: File Not Found')
                    } else {
                        res.writeHead(200, { 'Content-Type': 'text/html' })
                        res.write(data)
                    }
                    return res.end()
                })
        }
    })
    
    server.listen(port, function(error) {
        if (error) {
            console.log('Something went wrong', error)
        } else {
            console.log('Server is listening on port ' + port)
        }
    })
    

    (I'm far from expert in Node, so I'm not sure if that's the best way to do what it's doing, but it looks like it should work.)

    This next part, though, is plain javascript. It should be run in the browser, not on the server:

    var button = document.getElementById("meinButton")
    button.addEventListener("click", fetch.register_medication);
    

    The simplest way to accomplish that would be to store this in its own .js file, separate from the node scripts, and have each web page that needs it load it using <script src="/path/to/clientside.js">. (This path should be relative to the web root, just like for images or css files; it will not be the same as your nodejs paths). Node itself doesn't need to know anything about this .js file; it'll be requested directly by the browser and executed there.

    jsdom is part of Node which is used to perform DOM operations before sending the html to the browser, which is useful in some situations but for much more complicated use cases than what you're dealing with here. You can skip all that and go straight to the getElementById fun.

    (In a comment you mentioned trying to separate the js but getting the error "ReferenceError: document is not defined" -- that's a Node error message, which suggests that you were still trying to run the script on the server instead of in the browser. Make sure it's the web page itself, not node, that requests any js that should run in the browser.)