Propagating redirects to the top window
I have the following situation
I submit a form
- If there's an error, the server responds with the same form HTML fragment but with invalid inputs and error messages
- If the request was successful, the server responds with a 302 and intends to redirect to a different page, full page reload
My problem is that in the case of a successful request, the page I intend to redirect to is rendered replacing the form. The redirect does not propagate to the top window.
Has anyone found a way to do this?
You can change the script by including window.top, which refers to the topmost window
@Atmos4 Did you have an example of how to do this? Thank you 🙏
@lpil reading back what I said 9 months ago, I think I misunderstood the issue completely :D I had mistaken it for an issue with nested htmz frames.
To answer the issue properly this time, the limitation of htmz is that you can't change the target from the response, you can only set it in the request.
To bypass this limitation, I believe we could rewrite htmz to use only out-of-band swaps with ids. Here is a very basic example of what it would look like:
<script>
function htmz(frame) {
setTimeout(() =>
frame.contentDocument.body.childNodes.forEach((n) =>
document.getElementById(n.id)?.replaceWith(n)
);
);
}
</script>
<iframe hidden name=htmz onload="htmz(this)"></iframe>
or minified:
<iframe hidden name=htmz onload="setTimeout(()=>contentDocument.body.childNodes.forEach(n=>document.getElementById(n.id)?.replaceWith(n)))"></iframe>
Hope it helps and sorry for the confusion. Let me know if you want a full example using this technique.
That's a cool idea, neat!
I think that would not be enough to propagate redirects though. You could replace the whole page but it wouldn't change the URL or unload all the JavaScript.
Then you need to attach information to the response, a bit like HTMX headers.
Since we are not in control of the request object with htmz, we could add an attribute to the body of the returned response (for example hz-redirect) that contains the redirect information.
The associated extension would be (based from the extension section of the docs)
<script>
function htmz(frame) {
// redirect extension
let redirect = frame.contentDocument.body.getAttribute("hz-redirect")
if (redirect) window.top.location.replace(redirect)
setTimeout(() =>
document
.querySelector(frame.contentWindow.location.hash || null)
?.replaceWith(...frame.contentDocument.body.childNodes)
);
}
</script>
<iframe hidden name=htmz onload="htmz(this)"></iframe>
Let me know if that helps
When I needed to do this. I just returned a custom element which redirects, so like this:
customeElements.define("x-redirect", class extends HTMLElement {
constructor() {
super()
let url = this.dataset.url || "/"
document.location.href = url
}
}
And the the element:
<x-redirect data-url="/my/path/i/want/to/go/to"></x-redirect>