-
-
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'); | |
} | |
} | |
}); |
Hi @cferdinandi. I'm wondering, what's the reasoning for fetch
ing 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. 🤔
@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.
@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?
@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.
@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.
@JasonNeel Ok, so the idea is this...
- The HTML for a component is rendered ONLY on the server.
- 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. - 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.
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.
@JasonNeel Yea, you've got it! No client-side logic around that at all. You skip hydration entirely.
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!