最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

forms - Flash Flask messages with a fetch request from JavaScript - Stack Overflow

programmeradmin3浏览0评论

I've developed a cafe app using flask. I watched like 2 or 3 tutorials, and started to create as much as I could. Following this code from a form

<!-- login.html -->
<body>
    <h1>Login</h1>
    <div>
        {% for m in get_flashed_messages() %}
        <div>{{ m }}</div>
        {% endfor %}
    </div>

    <form method="POST">
        <label for="email">Email</label>
        <input type="text" name="email" id="email">
        <label for="password">Password</label>
        <input type="password" name="password" id="password">
        <input type="submit" id="submit" value="Login">
    </form>
</body>

and controller like this:

from flask import *

app = Flask(__name__)
app.secret_key = 'secret'
app.debug = True

@app.route("/", methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        email = request.form.get('email')
        pwd = request.form.get('password')
        
        if email and pwd:
            flash("Success!")
            return redirect(url_for('home'))
        else:
            flash("Email and password required!")
    return render_template('login.html')

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

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

When the form is not complete, after click submit button, the page "reloads" and displays the flashed message as expected in the same page, and also when is complete, displays the flashed message in home.html. That's Ok.

<!-- home.html -->
<!DOCTYPE html>
<html>
<body>
    <div>
        {% for m in get_flashed_messages() %}
        <div>{{ m }}</div>
        {% endfor %}
    </div>
    <h1>Logging successful</h1>
</body>
</html>

However, the issue is, when I try to do the "same" but from JavaScript with a fetch and JSON requests like this:

    <script>
        window.onload = function () {
            let email = document.getElementById('email');
            let pwd = document.getElementById('password');
            let submit = document.getElementById('submit');
            submit.addEventListener('click', async function () {
                let data = {'email': email.value,
                    'password': pwd.value
                };

                let request = {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(data)
                };
                let response = await fetch("/", request)
                console.log(response);
            });
        }
    </script>

It doesnt "reload" the page, more over it doesnt show the flashed messages as I would expect. I just want to submit data from JavaScript and, the flash messages to work as expected, show after the request is complete, as it were a form, but without a form. Is it that possible in first place? It's been a month and I cannot figure out how to do it, I'm giving up on this.

BTW I changed the <form> to <div> in order to send it not as form, and of course, read request.json for JS thing

I've read the documentation, but it only shows an example with form html method, that is what I wrote first.

I've also tried to see what is the response like let response = await fetch("/", data).then(r => r.text()) and it logs the HTML that **does contain** the flashed message. I mean, it's just right there, but it doesn't do anything about it, nor show the flashed messages. Also, I read that you can manually redirect with if(response.redirected) window.location.href = response.url And it redirects, but again no flash message are shown.

I wouldn't like to rewrite the HTML code like


document.open();
document.write(html);
document.close();

Because is only overlapping the HTML, and when reloads is not the actual page that was redirected in first place.

I've developed a cafe app using flask. I watched like 2 or 3 tutorials, and started to create as much as I could. Following this code from a form

<!-- login.html -->
<body>
    <h1>Login</h1>
    <div>
        {% for m in get_flashed_messages() %}
        <div>{{ m }}</div>
        {% endfor %}
    </div>

    <form method="POST">
        <label for="email">Email</label>
        <input type="text" name="email" id="email">
        <label for="password">Password</label>
        <input type="password" name="password" id="password">
        <input type="submit" id="submit" value="Login">
    </form>
</body>

and controller like this:

from flask import *

app = Flask(__name__)
app.secret_key = 'secret'
app.debug = True

@app.route("/", methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        email = request.form.get('email')
        pwd = request.form.get('password')
        
        if email and pwd:
            flash("Success!")
            return redirect(url_for('home'))
        else:
            flash("Email and password required!")
    return render_template('login.html')

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

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

When the form is not complete, after click submit button, the page "reloads" and displays the flashed message as expected in the same page, and also when is complete, displays the flashed message in home.html. That's Ok.

<!-- home.html -->
<!DOCTYPE html>
<html>
<body>
    <div>
        {% for m in get_flashed_messages() %}
        <div>{{ m }}</div>
        {% endfor %}
    </div>
    <h1>Logging successful</h1>
</body>
</html>

However, the issue is, when I try to do the "same" but from JavaScript with a fetch and JSON requests like this:

    <script>
        window.onload = function () {
            let email = document.getElementById('email');
            let pwd = document.getElementById('password');
            let submit = document.getElementById('submit');
            submit.addEventListener('click', async function () {
                let data = {'email': email.value,
                    'password': pwd.value
                };

                let request = {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(data)
                };
                let response = await fetch("/", request)
                console.log(response);
            });
        }
    </script>

It doesnt "reload" the page, more over it doesnt show the flashed messages as I would expect. I just want to submit data from JavaScript and, the flash messages to work as expected, show after the request is complete, as it were a form, but without a form. Is it that possible in first place? It's been a month and I cannot figure out how to do it, I'm giving up on this.

BTW I changed the <form> to <div> in order to send it not as form, and of course, read request.json for JS thing

I've read the documentation, but it only shows an example with form html method, that is what I wrote first.

I've also tried to see what is the response like let response = await fetch("/", data).then(r => r.text()) and it logs the HTML that **does contain** the flashed message. I mean, it's just right there, but it doesn't do anything about it, nor show the flashed messages. Also, I read that you can manually redirect with if(response.redirected) window.location.href = response.url And it redirects, but again no flash message are shown.

I wouldn't like to rewrite the HTML code like


document.open();
document.write(html);
document.close();

Because is only overlapping the HTML, and when reloads is not the actual page that was redirected in first place.

Share Improve this question asked Feb 14 at 21:09 shosholandashosholanda 11 bronze badge 2
  • 1 you can't redirect to another page with spesific haders and/or request body in JS and also you can't redirect using fetch or XMLHttpRequest so the only way i see here is make backend function which only check data and send response if data is ok or not then you get and read responce with fetch , show message (using js) and redirect in the end if needed – A_____ A_______ Commented Feb 14 at 22:17
  • If you need the functionality of a regular form (submit some data then load and display a new page) then using Ajax is unnecessarily complicating your life. Consider creating a hidden form, populating it via code, and calling its submit method. – James Commented Feb 14 at 22:48
Add a comment  | 

1 Answer 1

Reset to default 0

After one night of sleep, I only changed the header of the request to manual and if the type were opaqueredirect then redirect manually.

            submit.addEventListener('click', async function () {
            let data = {'email': email.value,
                'password': pwd.value
            };

            let request = {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                redirect: 'manual', //This line
                body: JSON.stringify(data)
            };
            let response = await fetch("/", request);
            console.log(response)
            if (response.type == "opaqueredirect"){
                window.location.href = response.url
                window.location.reload()
            }
            
        });

On browser I got HTTP status = 0, so after reading this it says that that empty response is just for frontend. Also the controller flash to a redirect always like return redirect(url_for('endpoint'))

    @app.route("/", methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            if request.is_json:
                email = request.json['email']
                pwd = request.json['password']
            else:
                email = request.form.get('email')
                pwd = request.form.get('password')
            print(email, pwd)
            if email and pwd:
                flash("Success!")
                return redirect(url_for('home'))
            else:
                flash("Email and password required!")
                return redirect(url_for('login'))
        return render_template('login.html')

I don't know if this is the best solution in terms of security or scalability but it fits my needs. Better solutions are welcome :)

发布评论

评论列表(0)

  1. 暂无评论