Skip to content

Instantly share code, notes, and snippets.

@pamelafox
Created September 28, 2021 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pamelafox/8a37eaa0473e52f1677da18b6520b032 to your computer and use it in GitHub Desktop.
Save pamelafox/8a37eaa0473e52f1677da18b6520b032 to your computer and use it in GitHub Desktop.
Auto-saving Rails form example
<!-- Auto-saving for Rails blog example -->
<h1>Editing Post</h1>
<p>Last saved:
<span id="last-saved-display" data-last-saved="<%= @post.updated_at.iso8601 %>">
</span>
<span id="save-status">
</span>
</p>
<%= render 'form', post: @post %>
<%= link_to 'Show', @post %> |
<%= link_to 'Back', posts_path %>
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/3.6.2/fetch.min.js" integrity="sha512-1Gn7//DzfuF67BGkg97Oc6jPN6hqxuZXnaTpC9P5uw8C6W4yUNj5hoS/APga4g1nO2X6USBb/rXtGzADdaVDeA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon@2.0.2/build/global/luxon.min.js" type="text/javascript"></script>
<script>
window.addEventListener("load", () => {
const postForm = document.getElementById("post_form");
const titleInput = document.getElementById("post_title");
const contentArea = document.getElementById("post_content");
const saveStatus = document.getElementById("save-status");
const saveTime = document.getElementById("last-saved-display");
let lastSavedTimer;
function updateLastSaved() {
const lastSavedISO = saveTime.getAttribute("data-last-saved");
saveTime.innerText = luxon.DateTime.fromISO(lastSavedISO).toRelative();
}
function onSave(responseJSON) {
saveStatus.innerText = "(Saved!)";
saveStatus.classList.remove("error");
saveTime.setAttribute("data-last-saved", responseJSON.updated_at);
if (lastSavedTimer) {
window.clearInterval(lastSavedTimer);
}
lastSavedTimer = window.setInterval(updateLastSaved, 5000);
updateLastSaved();
}
function onError() {
saveStatus.innerText = "(Error!)";
saveStatus.classList.add("error");
}
function autoSavePost() {
saveStatus.innerText = "(Saving...)";
const request = new XMLHttpRequest();
request.addEventListener("load", function() {
onSave(request.response);
});
request.addEventListener("error", function() {
onError();
});
request.responseType = "json";
request.open("POST", postForm.getAttribute("action") + ".json");
request.send(new FormData(postForm));
}
function autoSavePostFetch() {
saveStatus.innerText = "(Saving...)";
fetch(postForm.getAttribute("action") + ".json",
{method: "POST", body: new FormData(postForm)})
.then(response => {
if (!response.ok) {
onError();
}
return response.json();
})
.then(responseJSON => { onSave(responseJSON) })
.catch(onError);
}
titleInput.addEventListener("change", () => autoSavePostFetch());
contentArea.addEventListener("change", () => autoSavePostFetch());
updateLastSaved();
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment