Skip to content

Instantly share code, notes, and snippets.

@cferdinandi
Created February 13, 2025 17:24
Show Gist options
  • Save cferdinandi/7a04ea750b31d07288b18398c344292b to your computer and use it in GitHub Desktop.
Save cferdinandi/7a04ea750b31d07288b18398c344292b to your computer and use it in GitHub Desktop.
customElements.define('ajax-html', class extends HTMLElement {
/**
* The class constructor object
*/
constructor () {
// Always call super first in constructor
super();
// Get attributes
let eventNames = this.getAttribute('event-name')?.split(',') || [];
this.eventUID = this.getAttribute('event-uid')?.split(',') || [];
if (!eventNames.length || !this.id) return;
// Listen for events
for (let eventName of eventNames) {
document.addEventListener(eventName, (event) => {
this.updateHTML(event, this);
});
}
}
async updateHTML (event, instance) {
// Only run if event has the correct type
if (this.eventUID.length && !this.eventUID.includes(event.detail?.uid)) return;
try {
// Get the page
let request = await fetch(location.href);
if (!request.ok) throw request;
let response = await request.text();
// Convert to HTML
let parser = new DOMParser();
let html = parser.parseFromString(response, 'text/html');
// Get the updated HTML element
let newElem = html.querySelector(`#${instance.id}`);
if (!newElem) return;
// Replace it in the HTML
instance.replaceWith(newElem);
} catch (error) {
console.warn('Unable to update HTML');
}
}
});
@AmraniCh
Copy link

Hi Chris, thanks for sharing this. One small note is we can use jsdoc for method parameters like the type of instance parameter for updateHTML method, thanks!

@JasonNeel
Copy link

Hi @cferdinandi. I'm wondering, what's the reasoning for fetching the current page (line 33), when can't you just query the DOM of the component's parent document? Wouldn't that be more efficient? Something like let html = this.closest('html');? Then, you're not relying on an AJAX call to the current page, and it wouldn't need the extra step of parsing. I think I'm missing something here though. 🤔

@cferdinandi
Copy link
Author

@JasonNeel I don't understand the question. The component exists and is rendered on the current page, from the server. It's not loaded asynchronously from somewhere else.

@JasonNeel
Copy link

@cferdinandi Right, I understand that. What I don’t understand is AJAXing the current page, when the component itself could just query that by referencing the parent DOM structure, if that makes sense?

@cferdinandi
Copy link
Author

@JasonNeel I don't understand what you mean. I need to get a fresh copy of the URL from the server to get the current version of the HTML associated with that component. It's not rendered in a separate file somewhere or anything.

@JasonNeel
Copy link

JasonNeel commented Feb 18, 2025

@cferdinandi Yeah, I must be missing something here then. Sorry. In my head, there’s no reason to fetch the current page you’re on, unless the reason is to get the page in an unmodified state, which doesn’t make sense to me because I don’t think that would matter here.

@cferdinandi
Copy link
Author

@JasonNeel Ok, so the idea is this...

  1. The HTML for a component is rendered ONLY on the server.
  2. Somewhere else on that same page, a form sends data to the server (with JS/ajax) and modifies the data that was used to generate the component from item 1.
  3. Now, the item 1 component is out-of-sync with the data. So, you fetch a fresh copy of the HTML from the server, and update just the part that needs updating.

@JasonNeel
Copy link

Oh! I think I see what you’re getting at now. By having the server render the data, you don’t need to have any logic client-side to process the data into the HTML you need to update the page. Sorry. Major brain fart on my part. I had the assumption that something existed client side to render the data without needing the server.

@cferdinandi
Copy link
Author

@JasonNeel Yea, you've got it! No client-side logic around that at all. You skip hydration entirely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment