Skip to content

Instantly share code, notes, and snippets.

@swlkr
Last active May 13, 2024 18:33
Show Gist options
  • Save swlkr/4cbc11ebe6b3cbde711f1c1dbec17a04 to your computer and use it in GitHub Desktop.
Save swlkr/4cbc11ebe6b3cbde711f1c1dbec17a04 to your computer and use it in GitHub Desktop.
Quick and dirty htmx script
<!-- example -->
<!--
1. sends an X-Request header
2. follows redirects
3. automatically pushes the new redirected url
4. encodes forms as json so we don't need csrf tokens anymore
-->
<!-- your backend does not need to change, just redirect like normal -->
<!-- #posts and #count will both be updated on response -->
<form method="post" action="/posts" x-replace="posts count">
<input type="text" name="title" />
<button>post</button>
</form>
<div id="count">
total # of posts could be here
</div>
<!-- these can be anywhere on the page -->
<div id="posts">
posts may be here
</div>
const elements = document.querySelectorAll("form");
elements.forEach((element) => {
element.addEventListener("submit", (e) => {
e.preventDefault();
const method = element.getAttribute("method");
const action = element.getAttribute("action");
const replaceTargets = element.getAttribute("x-replace");
const updateTargets = element.getAttribute("x-update");
let formData = new FormData(element);
request(method, action, formData)
.then((text) => {
const dom = new DOMParser().parseFromString(text, "text/html");
if(replaceTargets) {
hitTargets(dom, replaceTargets, "replace");
}
if(updateTargets) {
hitTargets(dom, updateTargets, "update");
}
})
.catch((err) => {
console.error(err);
})
})
});
function hitTargets(dom, targets, merge) {
targets.split(" ").forEach((target) => {
const selector = `#${target}`;
const next = dom.querySelector(selector);
const current = document.querySelector(selector);
switch(merge) {
case "replace":
current.replaceWith(next);
break;
case "update":
current.innerHTML = "";
current.appendChild(next);
break;
}
});
}
async function request(method, url, formData) {
let options = {
method: method,
redirect: "follow",
headers: {
"Content-Type": "application/json",
"X-Request": "true"
}
};
if(formData) {
options.body = formDataToJson(formData);
}
const response = await fetch(url, options);
if(response.ok) {
if(response.redirected) {
history.pushState({}, "", response.url);
}
return await response.text();
} else {
return;
}
}
function formDataToJson(formData) {
if(!formData) { return; }
let body = {};
formData.forEach((value, key) => body[key] = value);
return JSON.stringify(body);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment