With multiple htmx.ajax requests only the first call is executed
When calling htmx.ajax multiple times only the first call is actually executed.
For example when executing the code below. Only my-page-1 is requested.
htmx.ajax("GET", `/my-page-1.html`);
htmx.ajax("GET", `/my-page-2.html`);
It seems like the my-page-2 call is cancelled.
Reproduction link is here
Im having a similar issue, except that only the second request is executed.
My solution was to use fetch to retrieve data and then insert the result into the DOM using JavaScript. I stopped using htmx for this problem.
Hey, you might want to take a look at hx-sync
drop - drop (ignore) this request if an existing request is in flight (the default)
By default, if a second request is fired on an element that already has one in flight, that new request will be dropped thus cancelled
What may not be intuitive in your case here, is that calling htmx.ajax without the third parameter will default using the body as the source element of your requests. So with the default hx-sync strategy, any request happening while one is already in flight will be ignored
You could:
- Define
hx-sync="queue all"for example on your body element - Use different elements as the source of your
htmx.ajaxcalls so they don't even collide at all
Having a similar issue but for me the second request is not running.
htmx.ajax('GET', "/cart/products", {target:"#cart_products", swap:"innerHTML"});
htmx.ajax('GET', "/cart/summary", {target:"#cart_summary", swap:"innerHTML"});
htmx.ajax('GET', "/cart/products_count", {target:"#cart_product_count", swap:"innerHTML"});
this:queue all does not seem to be working on the body tag. I'll try to investigate this further @Telroshan
I'm having trouble understanding when is the queuedRequest supposed to be cleared in the issueAjaxRequest function. It seems to only occur when a new request is sent, yet while debugging I've found that the htmx internal data sometimes resets, causing the queue to reset (no idea why or what's causing it)? And even then, shouldn't the queue sending requests as the element becomes free rather than waiting for a new request? Or maybe I'm just misunderstanding the source code. For further clarity on the problem, my goal is to make the below work:
<!DOCTYPE html>
<html>
<head>
<script src="htmx.js"></script>
</head>
<body hx-sync="this:queue all">
<p id="questionid123">first</p>
<p id="questionid124">second</p>
<p id="questionid125">third</p>
<p id="questionid0">fourth</p>
<script>
setTimeout(() => htmx.ajax('GET', '/question/partial?fieldId=0', { source: "body", target: '#questionid0'}), 2000);
var array= ['123','124','125'];
for(i=0;i<array.length;i++) {
htmx.ajax('GET', '/question/partial?fieldId='+array[i], { source: "body",
target: '#questionid'+array[i] });
}
</script>
</body>
</html>
This issue arises when ajax is called while other requests sent via ajax are still in fight, even when the targets are different elements. The root cause has to do with the XHR being stored on the internal data for the target elements and the fact that, for some reason, ajax is using the internal data for the body element even when a target parameter is provided. Thus, it seems to get confused and think there's already a request in flight for the body element when if it were doing the right thing it wouldn't necessarily think there are any requests in flight for the body.
I fixed the issue for myself with the following change:
/**
* Issues an htmx-style AJAX request
*
* @see https://htmx.org/api/#ajax
*
* @param {HttpVerb} verb
* @param {string} path the URL path to make the AJAX
* @param {Element|string|HtmxAjaxHelperContext} context the element to target (defaults to the **body**) | a selector for the target | a context object that contains any of the following
* @return {Promise<void>} Promise that resolves immediately if no request is sent, or when the request is complete
*/
function ajaxHelper(verb, path, context) {
verb = (/** @type HttpVerb */(verb.toLowerCase()))
if (context) {
if (context instanceof Element || typeof context === 'string') {
- return issueAjaxRequest(verb, path, null, null, {
+ return issueAjaxRequest(verb, path, resolveTarget(context), null, {
targetOverride: resolveTarget(context),
returnPromise: true
})
} else {
return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event,
{
handler: context.handler,
headers: context.headers,
values: context.values,
targetOverride: resolveTarget(context.target),
swapOverride: context.swap,
select: context.select,
returnPromise: true
})
}
} else {
return issueAjaxRequest(verb, path, null, null, {
returnPromise: true
})
}
}
I don't understand why it was passing null for the elt parameter to issueAjaxRequest, so maybe this will have some unintended consequences, but it fixed this issue for me.
HTH and happy to collab more on this.
I'll roll with this change for now and if it doesn't cause me any trouble I'll issue a PR (if I don't forget ;))
fwiw, the above solution is still working fine for me, but I see that the maintainers don't want PRs without explicitly asking for them, so there's nothing for me to do for now. Their automated tests are also cool with this change.
Sorry I meant to test this as well but I've not gotten to it yet. I'll be sure to test this on my end as well. But thank you for your work!
I see that the maintainers don't want PRs without explicitly asking for them
Only for new features @patreeceeo ! Cf the contribution guidelines
- Please do not PR new features unless you have already made an issue proposing the feature, and had it accepted by a core maintainer.
- Correspondingly, it is fine to directly PR bugfixes for behavior that htmx already guarantees
You're ofc welcome to submit a bugfix PR. We'll then investigate on whether this is the best fix or not, make sure it doesn't break anything etc., but you can open that FR if you feel like it
Oh, I totally misread... I'll open that bugfix PR.