.


3gp Mp4 HD
Play/Download
Live 3D App
Search.Pencarian Menu

Add text send email to rh3252705.adda@blogger.com or Click this (Text porn Will delete) | Tambah teks kirim email ke rh3252705.adda@blogger.com atau Klik ini (Teks porno akan dihapus)
Total post.pos : 17453+

[Go Make Things] How to dynamically update content with an HTML Web Component

Over the last few days, we looked at how I build web apps using forms and a PHP backend, with a Web Component to make it ajaxy.

Today, we're going to learn how to update other parts of the page whenever one of those ajax-based form updates happens.

Let's dig in!

An example

Let's say you've got a form that you use to add items to a list.

You're using the <ajax-form> Web Component to asynchronously send the the form data to the backend, and display a success message when the item is added.

<ajax-form>  	<form action="/path/to/add-item.php" method="POST">  		<label for="item">The New Item</label>  		<input type="text" name="item" id="item" required>  		<button>Add Item</button>  		<div role="status"></div>  	</form>  </ajax-form>

Elsewhere on the page, you also have section that lists the items you've added.

<?php     	// Reads a flat JSON file  	// returns an array of stuff  	$user_stuff = get_user_stuff();    	if empty($user_stuff) :  ?>  	<p>You don't have any items yet. Add one to get started.</p>  <?php else : ?>  	<p>Your stuff...</p>  	<ul>  	<?php foreach ($user_stuff as $key => $item) : ?>  		<li><?php echo $item ?></li>  	<?php endforeach; ?>  	</ul>  <?php endif; ?>  

The <ajax-form> element handles the <form> element: sending data, showing a message in the UI, and clearing the form when the item is added.

But how do you also update the list of stuff without reloading the page?

An <ajax-html> Web Component

There are a few ways you could do this, but I created an <ajax-html> Web Component that wraps around any content that should be updated after an asynchronous update to the page.

It wraps around any of the content that should be updated, and requires three attributes: a unique [id], an [event-name], and an (optional) [event-uid].

<ajax-html   	id="user-stuff-list"   	event-name="ajax-form"   	event-uid="list-updated"  >  	<?php     		// Reads a flat JSON file  		// returns an array of stuff  		$user_stuff = get_user_stuff();    		if empty($user_stuff) :  	?>  		<p>You don't have any items yet. Add one to get started.</p>  	<?php else : ?>  		<!-- The list stuff... -->  	<?php endif; ?>  </ajax-html>  

About the attributes

The event-name is the name of the event or events to listen for.

In yesterday's article, I mentioned that the <ajax-form> element emits an ajax-form event when a form is successfully completed. That's the event I want to listen for here.

You might also have other events that trigger asynchronous updates on the page. If that's the case, you can pass those in two, as a comma-separated list: [event-name="ajax-form,ajax-watch-later"].

Similarly, you might have multiple <ajax-form> elements on the page, but only one of them should cause your content to update.

In my PHP backend, I'll add a uid to the API response, like this…

<?php    // Return success  send_response(array(  	'uid' => 'list-updated',  	'message' => 'The item was added to your list.',  ), 200, $referrer, $query);  

I can then pass that uid (or multiple ones, if needed) as attributes. The Web Component will ignore any events that don't have that attribute.

Instantiating the Web Component

Like any Web Component, this one starts by defining the custom element, passing in a class, and running super() in the constructor() method.

(If you're new to Web Components, I've got a short tutorial on writing your first one here.)

customElements.define('ajax-html', class extends HTMLElement {    	/**  	 * The class constructor object  	 */  	constructor () {    		// Always call super first in constructor  		super();    	}    });  

Next, I get my attributes and save them to instance properties.

Since to the [event-name] and [event-uid] attributes could have comma-separated lists of multiple items, I use the optional chaining operator and the Array.prototype.split() method to get an array of items.

If there are no eventNames or there's no id set on the custom element, I return to end the instantiation.

/**   * 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;    }  

Otherwise, I add an event listener to the document for each eventName.

When the event triggers, I run an updateHTML() method, passing in the event and the current instance as arguments.

(I was having trouble getting the handleEvent() method to work properly for this setup.)

/**   * The class constructor object   */  constructor () {    	// ...  	if (!eventNames.length || !this.id) return;    	// Listen for events  	for (let eventName of eventNames) {  		document.addEventListener(eventName, (event) => {  			this.updateHTML(event, this);  		});  	}    }  

Getting the new HTML

Now for the fun part: actually updating the HTML on the page!

Because we'll be making asynchronous updates, I use the async operator with my updateHTML() method. This will let me use the await operator in my code.

Inside the method, I first check if there's an eventUID specified for the instance. If so, I use the Array.prototype.includes() method to check if the event.detail.uid (if one was provided) is a match.

If not, I return to end the method early.

async updateHTML (event, instance) {    	// Only run if event has the correct type  	if (this.eventUID.length && !this.eventUID.includes(event.detail?.uid)) return;    }  

Since I'll be making an API call, I setup a try-catch block. This will let me handle errors with the API call.

On an error, I'll console.warn() a message, but do nothing else.

async updateHTML (event, instance) {    	// Only run if event has the correct type  	if (this.eventUID.length && !this.eventUID.includes(event.detail?.uid)) return;    	try {  		// Do API stuff...  	} catch (error) {  		console.warn('Unable to update HTML');  	}    }  

I want to get a fresh copy of the current page's HTML, find this Web Component, and replace its HTML with the latest content from the server.

First, I fetch() the current URL—the location.href property—and use the await operator to wait for a response. This will return the full HTML file for the current page.

If there's an error, I throw request.

Otherwise, I use the Request.text() method to get the returned HTML string. This is also asynchronous, so I again use await.

try {    	// Get the page  	let request = await fetch(location.href);  	if (!request.ok) throw request;  	let response = await request.text();    }  

Now, I have new HTML to replace the current HTML with.

Updating the HTML

To get the actual HTML elements to use, I need to convert the response HTML string into real HTML elements.

But I want to do that without rendering it into an actual DOM yet. For that, I can use the DOMParser() method.

I create a new DOMParser(), then pass in the response string as text/html. This returns an html document that's not rendered anywhere.

I can then use the Element.querySelector() method to find the current Web Component, using the instance.id as a selector. If I don't find one, I'll return to bail.

Otherwise, I'll use the Element.replaceWith() method to swap out the current Web Component with the latest one from the server.

try {    	// ...  	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);    }  

When that happens, the browser will garbage collect any event listeners, the new Web Component will instantiate, and the process will repeat as needed.

Wrapping up

You can download the entire <ajax-html> element on GitHub. I'll also be adding it to my members toolkit.

If you have any specific questions about how I build apps like this, or something else you'd like me to write about, let me know!

Like this? A Go Make Things membership is the best way to support my work and help me create more free content.

Cheers,
Chris

Want to share this with others or read it later? View it in a browser.

Share :

Facebook Twitter Google+ Lintasme

Related Post:

0 Komentar untuk "[Go Make Things] How to dynamically update content with an HTML Web Component"

Back To Top