Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When using HX-Redirect, the htmx:afterRequest event's detail.successful and detail.failed fields are undefined #2523

Open
luontola opened this issue May 1, 2024 · 0 comments

Comments

@luontola
Copy link

luontola commented May 1, 2024

When the server returns a HX-Redirect header, the htmx:afterRequest event for that request will not tell whether the request was successful or failed. The event.detail.successful and event.detail.failed are both undefined.

The expected behavior would be that the successful and failed fields will always be present.

On related note, the fields are also missing if the browser is in offline mode. I think those too should be categorized as failed requests.

This happens with htmx 1.9.12 and 2.0.0-beta3

Reproducing

from flask import Flask, Response, request

app = Flask(__name__)


@app.route("/")
def home():
    return """
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
<script type="module">
document.body.addEventListener('htmx:afterRequest', event => {
    console.log(event);
    console.log('status: ' + event.detail.xhr.status);
    console.log('successful: ' + event.detail.successful);
    console.log('failed: ' + event.detail.failed);
    // Some error handling code:
    if (event.detail.successful) {
        console.log('Request successful.');
    } else if (event.detail.failed) {
        console.log('Request failed.');
        alert('Request failed.');
    } else {
        console.log('Unknown error. Probably network is down.');
        alert('Unknown error. Probably network is down.');
    }
});
</script>

<h1>Home</h1>
<p><button hx-get="/clicked?scenario=1" hx-swap="outerHTML">Button 1: successful</button></p>
<p><button hx-get="/clicked?scenario=2" hx-swap="outerHTML">Button 2: error from backend</button></p>
<p><button hx-get="/clicked?scenario=3" hx-swap="outerHTML">Button 3: hx-redirect (BUG: thought to be a network error)</button></p>
<p><a href="/">Restart</a></p>
"""


@app.route("/clicked")
def clicked():
    resp = Response("<h3>Clicked</h3>")
    scenario = request.args.get('scenario')
    if scenario == "1":
        resp.status = 200
    if scenario == "2":
        resp.status = 400
    if scenario == "3":
        # BUG: If the HX-Redirect header is present, the successful/failed fields will be undefined.
        resp.status = 200
        resp.headers["HX-Redirect"] = "/redirected"
    return resp


@app.route("/redirected")
def redirected():
    return """
<h1>Redirected</h1>
<p><a href="/">Restart</a></p>
"""

Run the above app with the commands:

pip install Flask
flask --app server.py --debug run

Visit http://127.0.0.1:5000/ and click each of the buttons while observing what is printed to the console.

Buttons 1 and 2 work correctly.

But when you click Button 3, the htmx:afterRequest event will be missing the event.detail.successful and event.detail.failed fields. The app will print the following to the console and its error handler will show an error popup. (In a real app that doesn't use alert(), the error message would flash for a fraction of a second before redirecting to the next page).

status: 200
successful: undefined
failed: undefined

Those fields are also missing when the browser is in offline mode. (This article told to use that to detect network errors. I'm not sure if that is expected behavior.)

Set the browser to offline mode in the Chrome DevTool's Network tab and click any of the three buttons to see that behavior.

Workaround

Ignore the event.detail.successful and event.detail.failed fields, and instead check the HTTP status code in event.detail.xhr.status yourself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant