简体   繁体   中英

How can i appropriately serve a static js file integrated with flask?

I am currently going through the Web Programming with Python and Javascript via EDX. Specifically, I am on the part utilizing Socket.IO. I have come across an error that I am not quite sure how to fix and was wondering if anyone could help. This is source code from the course itself.

The file structure:

-venv
     -static
            -index.js
     -templates
            -index.html
     -application.py

Here is application.py:

import os

from flask import Flask, jsonify, render_template, request
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
socketio = SocketIO(app)

votes = {"yes": 0, "no": 0, "maybe": 0}


@app.route("/")
def index():
    return render_template("index.html", votes=votes)


@socketio.on("submit vote")
def vote(data):
    selection = data["selection"]
    votes[selection] += 1
    emit("vote totals", votes, broadcast=True)

Here is index.js:

document.addEventListener('DOMContentLoaded', () => {

    // Connect to websocket
    var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);

    // When connected, configure buttons
    socket.on('connect', () => {

        // Each button should emit a "submit vote" event
        document.querySelectorAll('button').forEach(button => {
            button.onclick = () => {
                const selection = button.dataset.vote;
                socket.emit('submit vote', {'selection': selection});
            };
        });
    });

    // When a new vote is announced, add to the unordered list
    socket.on('vote totals', data => {
        document.querySelector('#yes').innerHTML = data.yes;
        document.querySelector('#no').innerHTML = data.no;
        document.querySelector('#maybe').innerHTML = data.maybe;
    });
});

Here is index.html:

<html>

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js">
    </script>
    <script type="text/javascript" src="{{url_for('static', filename='index.js')}}"></script>
    <title>Vote</title>
</head>

<body>
    <div>Yes Votes: <span id="yes">{{ votes["yes"] }}</span></div>
    <div>No Votes: <span id="no">{{ votes["no"] }}</span></div>
    <div>Maybe Votes: <span id="maybe">{{ votes["maybe"] }}<span></div>
        <hr>
        <button data-vote="yes">Yes</button>
        <button data-vote="no">No</button>
        <button data-vote="maybe">Maybe</button>      
    </body>

</html>

The problem I am experiencing is that the application as is doesn't work. It will only work if I directly insert the js directly into the HTML file. For some reason serving it as a static file doesn't work. When I try to serve it as a static file I do have a console error stating "Uncaught TypeError: Cannot set property 'onclick' of null". I am assuming the issue is that the content isn't loaded by the time the script runs however moving the script around on the html page does not seem to do anything. Does any have any suggestions?

Thank you.

The solution to this problem was to insert index.js into a js folder in the static folder and moving the script to the bottom of the body.

Final HTML code:

<!DOCTYPE html>
<html>

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js">
    </script>
    <title>Vote</title>
</head>

<body>
    <div>Yes Votes: <span id="yes">{{ votes["yes"] }}</span></div>
    <div>No Votes: <span id="no">{{ votes["no"] }}</span></div>
    <div>Maybe Votes: <span id="maybe">{{ votes["maybe"] }}<span></div>
        <hr>
        <button data-vote="yes" id="yesvote">Yes</button>
        <button data-vote="no" id="novote">No</button>
        <button data-vote="maybe" id="maybevote">Maybe</button>  
        <script type="text/javascript" src="{{url_for('static', filename='js/index.js')}}"></script>    
    </body>

</html>

First, You need to put the javascript files in the static/js folder. Also, the reason you are getting cannot set property of undefined is a problem in your HTML code where you set an id to the number of votes. You are supposed to set an id to the button tags. Here is the solution:

<html>

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js">
    </script>
    <script type="text/javascript" src="{{url_for('static', filename='index.js')}}"></script>
    <title>Vote</title>
</head>

<body>
    <div>Yes Votes: <span>{{ votes["yes"] }}</span></div>
    <div>No Votes: <span>{{ votes["no"] }}</span></div>
    <div>Maybe Votes: <span>{{ votes["maybe"] }}<span></div>
        <hr>
        <button data-vote="yes" id="yes">Yes</button>
        <button data-vote="no" id="no">No</button>
        <button data-vote="maybe" id="yes">Maybe</button>      
    </body>

</html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM