bigskysoftware / bigskysoftware/htmx
`hx-target` + `hx-swap="outerHTML"` causes errors with parallel `hx-get` requests
- Dominant language
- JavaScript
- Stars
- 49.4k
- Forks
- 1.7k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 30
Description
Demo code here of the issue: https://github.com/jwendel/scratch/tree/main/htmx-multi-request
possible related issue: https://github.com/bigskysoftware/htmx/issues/2440
## High-level
HTMX (`htmx.org@1.9.12`) is printing this in the Chrome console in my demo project if I switch quickly between the radio buttons:
```
TypeError: Cannot read properties of null (reading 'querySelector')
at htmx.js:903:46
at forEach (htmx.js:421:21)
at handleAttributes (htmx.js:898:13)
at insertNodesBefore (htmx.js:934:13)
at swapOuterHTML (htmx.js:1018:17)
at swap (htmx.js:1086:21)
at selectAndSwap (htmx.js:1150:24)
at doSwap (htmx.js:3626:25)
at handleAjaxResponse (htmx.js:3740:21)
at xhr.onload (htmx.js:3332:21)
```
And after this happens, the buttons that threw this error get stuck and stop sending hx-get requests to the server.
## Reason
Here is the problem HTML code:
```HTML
blue
green
```
And the call to `/dostuff` returns:
```html
```
Stepping through this a bunch, I believe the issue is that when you use `hx-target` along-side `hx-get`, HTMX remembers the target element (it does a query for it before sending the request), so when the XHR response comes in, it has a reference to the object (specifically the `responseInfo` object here: https://github.com/bigskysoftware/htmx/blob/15243b5d43e148934bbca7deb1028570afcd76ad/src/htmx.js#L3339. When the first response comes in, the div is replaced. When the second comes in, it tries to replace the remembered div, but it had been replaced in the DOM already (so it gives an error).
Steps to cause this:
1) You have 2 elements that set `hx-target` to the same target div
2) You set `hx-swap="outerHTML"` on both
3) Both elements issue XHR requests (`hx-get` in my case) in an overlapping fashion.
## Workarounds:
I think there are 2 workarounds
1) Don't use `hx-swap=outerHTML` if you can get multiple requests going at the same time. I switched the setup to use `hx-swap="innerHTML"` and it worked just fine with multiple requests.
2) use `hx-sync`. Specially I did `hx-sync="#updateme:replace"` on all the radio buttons and it resolved the issue by aborting the requests, so no request could try to update the `div` that was replaced before we get a response.
## Solution idea
`hx-target` shouldn't remember the full object at the start of the request (do the DOM query for it again).
Contributor guide
Assessment
This issue has not been assessed yet.