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.
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.
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