Open yopoyka opened 8 months ago
if you want to update an existing task, you can send the new task like
<div id="task-(unique id)" hx-swap-oob="outerHTML"></div>
instead of the wrapped task.
It will swap the task inline.
Thanks. But it doesn't solve the problem when task doesn't exist.
Any luck finding a solution? The closest I got so far is to include have a hx-swap-oob delete div preceding the hx-swap-oob beforeend div. It works but the replaced element will be moved. I would expect beforeend to replace the appropriate id first and only append if its not found.
No. I've came up with the same solution as yours. You can try to sort items using js on the client if it fits the application. I've also tried to play with extension api as it allows you to extend swap mechanism but I did not have much time to explore it more. I suggest you to look into it.
Hey, have you tried idiomorph?
If it works, you may be happy with HTMX v2 coming up. Iirc it will inherit some of the morph magic from it.
I've had a similar issue where I wanted to prepend elements to a list (using sse instead of websockets).
Hacked my way around the issue using a small htmx extension:
let internalApi = null;
htmx.defineExtension('oob-if-exists', {
init: function (api) {
internalApi = api;
},
transformResponse: function (text, xhr, elt) {
const fragment = internalApi.makeFragment(text);
const swapAttr = elt.getAttribute('hx-swap');
if (swapAttr == 'afterbegin' || swapAttr == 'beforeend') {
const elements = htmx.findAll(fragment, "[hx-swap-oob=if-exists]");
for (const element of elements) {
const selector = '#' + element.id;
const existingElement = htmx.find(selector);
if (!!existingElement) {
// Move element to the desired spot and swap the HTML
existingElement.parentNode.insertAdjacentElement(swapAttr, existingElement);
element.setAttribute('hx-swap-oob', 'innerHTML');
} else {
// Just create the element
element.removeAttribute('hx-swap-oob');
}
}
}
const htmlContent = [].map.call(fragment.childNodes, x => x.outerHTML).join('');
return htmlContent;
}
});
This is the source of the page:
<ol class="task-list" hx-ext="oob-if-exists" sse-swap="update-task" hx-swap="afterbegin">
</ol>
With something like this for the tasks:
<li id="task-1" hx-swap-oob="if-exists">Test</li>
This extension removes the hx-swap-oob
attribute if its id isn't in the document yet. This will make sure the entries are created if they don't yet exist, but swapped when they are.
It's a bit hacky, but seems to work fine for my use-case and can probably be adapted for yours.
What you need is really a binary swap target specification... If selector matches anything do one swap, otherwise do another swap.
So at the very least you'd need two selectors to specify both branches. Currently htmx doesn't seem to allow for that.
Maybe something to be added like hx-alt-target
that triggers when the main target returns nothing...
Hey! Here is how I did it; if adding items with hx-swap="before end"
you could use this javascript code to remove the first child or the last, depending on your use case
<script>
function handleNewItem() {
const container = document.getElementById(containerId);
const lastChild = container.lastElementChild;
if (lastChild) {
const elements = document.querySelectorAll(`#${lastChild.id}`);
if (elements.length > 1) {
elements[0].parentNode.removeChild(elements[0]);
}
}
}
</script>
What it does is search for all the elements with that ID usually two HTML elements with the same ID will appear when create We either remove the first one or the last one when inserting it! If a duplicate is found
hx-on::after-request=function();
The problem:
I have an element with id task-list.
It contains a list of elements representing tasks. Each of them has a unique id. Task-list connects to a websocket endpoint and listens for updates. Each update consists of html that wraps a task in order to swap it correctly.
It works for additions and deletions of tasks but not for updates.
I'm trying to do the following:
If task with id exists in the list swap it Else add the new task to the list
I don't see a way to achieve this behavior without extending htxm.