Last active
May 13, 2024 18:33
-
-
Save swlkr/4cbc11ebe6b3cbde711f1c1dbec17a04 to your computer and use it in GitHub Desktop.
Quick and dirty htmx script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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