Search code examples
javascriptpythonhtmlflaskweb-applications

"Flask and JavaScript Password Generator: Unable to Display Generated Password on Webpage


So im working on a Project for my self to learn flask. I wrote a Password generator who generates a Password based on the user's input. I wrote a function how sends the user inputs to the generator and then collects the response how gets send in json format. So when i click my button "Generate Password" it should print out the password. To see if the password even gets generated and sent, i put a console.log(data.password) so it prints it out in the console. enter image description here

So you can see the password gets generated but somehow i cant print it out on my Webpage. Can someone help me and tell my what the Problem is?

app.py

from flask import Flask, render_template, request, send_from_directory, jsonify
import random
import string
from tkinter import filedialog
from tkinter import messagebox

app = Flask(__name__)

password_label = None

def generate_password(length, characters):
    password = ''.join(random.choices(characters, k=length))
    return password

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/generate', methods=['POST'])
def generate():
    
    try:
        length = int(request.form.get('length'))
        characters = request.form.get('characters')
        
        if characters == 'letters':
            characters = string.ascii_letters
        elif characters == 'letters_digits':
            characters = string.ascii_letters + string.digits
        elif characters == 'all':
            characters = string.ascii_letters + string.digits + string.punctuation
        
        password = generate_password(length, characters)
        
        return jsonify(password=password)
    except Exception as e:
        return jsonify(error=str(e))

if __name__ == '__main__':
    app.run(debug=True)

and here is my "index.html":

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Password Generator</title>
</head>
<body>
    <h1>Password Generator</h1>
    
    <form action="/generate" method="POST" id="password-form">
        <label for="length">Password Length:</label>
        <input type="number" id="length" name="length" required><br><br>
        
        <label for="characters">Character Set:</label>
        <select id="characters" name="characters">
            <option value="letters">Letters</option>
            <option value="letters_digits">Letters and Digits</option>
            <option value="all">All Characters</option>
        </select><br><br>
        
        <input type="button" value="Generate Password" onclick="generatePassword()">
        
    </form>
  
    <br>
    <br>
        
    <div>
        {% if password %}
        <h2>Your generated password:</h2>
        <p id="generated-password" type="text" value="..."> {{ password }}</p>
{% endif %}
        
    </div>


    <script>
        function generatePassword() {
            const length = document.getElementById('length').value;
            const characters = document.getElementById('characters').value;
            
            const form = document.getElementById('password-form');

            const formData = new FormData(form);
            formData.append('length', length);
            formData.append('characters', characters);

            
            fetch('/generate', {
            method: 'POST',
            body: formData

            })
            .then(response => response.json())
            .then(data => {
                console.log(data.password);  // Debugging
                document.getElementById('generated-password').innerText = data.password;


            })
            .catch(error => {
                console.error('Error:', error);
            });
        }
    </script>
</body>
</html>

My goal is to print out the password on the Webpage.


Solution

  • i don't think you're passing password to your jinja template, making you miss the if block (because there is no password) and not rendering a field with id generate-password. Later trying to get an element with that id returns null in your javascript, on which you try to access InnerText causing your error.

    {% if password %}
        <h2>Your generated password:</h2>
        <p id="generated-password" type="text" value="..."> {{ password }}</p>
    {% endif %}
    

    you should either add an else block in this if block like this

    {% if password %}
        <h2>Your generated password:</h2>
        <p id="generated-password" type="text" value="..."> {{ password }}</p>
    {% else %}
        <!--create the fields empty if no password was generated-->
        <h2>Your generated password:</h2>
        <p id="generated-password" type="text" value="..."></p>
    {% endif %}
    

    or pass the value of the generated password via your render_template function like this

    return render_template('index.html',password=generate_password(8,string.ascii_letters + string.digits + string.punctuation))
    

    edits can be made as follows

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Password Generator</title>
    </head>
    <body>
        <h1>Password Generator</h1>
        <!--https://flask.palletsprojects.com/en/2.3.x/patterns/flashing/-->
        {% with messages = get_flashed_messages() %}
            {% if messages %}
                <ul class=flashes>
                    {% for message in messages %}
                        <li>{{ message }}</li>
                    {% endfor %}
                 </ul>
            {% endif %}
         {% endwith %}
        <form action="/generate" method="POST" id="password-form">
            <label for="length">Password Length:</label>
            <input type="number" id="length" name="length" required><br><br>
            
            <label for="characters">Character Set:</label>
            <select id="characters" name="characters">
                <option value="letters" selected>Letters</option>
                <option value="letters_digits">Letters and Digits</option>
                <option value="all">All Characters</option>
            </select><br><br>
            
            <input type="submit" value="Generate Password">
        </form>
        <br>
        <br>
        <div>
            {% if password %}
                <h2>Your generated password:</h2>
                <p id="generated-password" type="text" value="..."> {{ password }}</p>
            {% endif %}
            
        </div>
    </body>
    </html>
    

    and your python code like

    from flask import flash
    @app.route('/generate', methods=['POST'])
    def generate():
        try:
            length = int(request.form.get('length'))
            characters = request.form.get('characters')
            
            if characters == 'letters':
                characters = string.ascii_letters
            elif characters == 'letters_digits':
                characters = string.ascii_letters + string.digits
            elif characters == 'all':
                characters = string.ascii_letters + string.digits + string.punctuation
            
            password = generate_password(length, characters)
            
            return render_template("index.html",password=password)
        except Exception as e:
            flash(str(e))
            return render_template("index.html")
    

    the second solution generates a default value, though considering you want the user to fill in a form first i'd like to point you to the first method

    to be honest though, you don't need the if block here