Ad/iklan :







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 : 13631+

[Go Make Things] Callbacks on Web Components?

On a recent YouTube video of mine, I was asked…

How do you pass callback functions as props to a web component?

Specifically, I want to create a form web component that accepts three callback functions as input:

  1. beforeSubmit: a function to execute before the form is submitted
  2. afterSubmit: a function to execute after the form is submitted
  3. onSubmit: a function to execute while the form is being submitted

What are the best practices for passing these callback functions as props to the web component?

This is a great question! Let's dig in!

Don't use callbacks

With a typical JavaScript library, you pass callbacks in as part of the instantiate process.

new AjaxForm('#form-element', {  	beforeSubmit: function () {},  	afterSubmit: function () {},  	onSubmit: function () {}  });  

Because Web Components self-instantiate, though, there's no easy way to do that.

<ajax-form>  	<form>  		<!-- ... -->  	</form>  </ajax-form>

You could theoretically use global named functions and pass them in as attributes…

<ajax-form before-submit="doTheThing">  	<!-- ... -->  </ajax-form>

Or attach methods to the element after-the-fact…

let form = document.querySelector('ajax-form');  form.beforeSubmit = function () {};  

But this is, in my opinion, the wrong tool for the job.

Don't use callback functions at all. Instead, use custom events.

Custom Events

JavaScript provides developers with a way to emit custom events that developers can listen for with the Element.addEventListener() method.

We can use custom events to let developers hook into the code that we write and run more code in response to when things happen. They provide a really flexible way to extend the functionality of a library or code base.

And, they're the perfect fit for something like a Web Component!

How to create a custom event

You can create a custom event with the new CustomEvent() constructor.

Pass in the name of the event as an argument. You can optionally pass in an object of options: whether or not the event bubbles, whether or not it's cancelable, and any detail you want shared with the event object.

The options.detail property can be any type of data, including an array or object.

// Create the event  let event = new CustomEvent('my-custom-event', {  	bubbles: true,  	cancelable: true,  	detail: 'This is awesome. I could also be an object or array.'  });  

After creating your event, you pass it into the Element.dispatchEvent() method to emit it.

You can emit your event on any element. For Web Components, the custom element is often the right choice.

// Emit the event  this.dispatchEvent(event);  

Using a custom event in a Web Component

Using the question from my video as an example, let's imagine we have an <ajax-form> Web Component that runs some code when a form is submitted.

customElements.define('ajax-form', class extends HTMLElement {    	/**  	 * Instantiate the component  	 */  	constructor () {    		// Gives element access to the parent class properties  		super();    		// Get the form  		this.form = this.querySelector('form');    		// Listen for submit events  		this.addEventListener('submit', this);    	}    	/**  	 * Handle submit events  	 * @param  {Event} event The event object  	 */  	handleEvent (event) {  		// Do stuff with the form...  	}  }  

Since we'll be emitting multiple custom events, let's create an emit() method to do the heavy lifting for us…

customElements.define('ajax-form', class extends HTMLElement {    	/**  	 * Instantiate the component  	 */  	constructor () {  		// ...  	}    	// ...    	/**  	 * Emit a custom event  	 * @param  {String} type   The event name suffix  	 * @param  {Object} detail Details to include with the event  	 */  	emit (type, detail = {}) {    		// Create a new event  		let event = new CustomEvent(`ajax-form:${type}`, {  			bubbles: true,  			cancelable: true,  			detail: detail  		});    		// Dispatch the event  		return this.dispatchEvent(event);    	}  }  

Now, inside our handleEvent() method, we can emit our custom events…

/**   * Handle submit events   * @param  {Event} event The event object   */  handleEvent (event) {    	// Emit an event before submitting the form  	this.emit('before-submit');    	// Emit an event while submitting the form  	this.emit('submit');  	// Do stuff with the form...    	// Emit an event after submitting the form  	this.emit('after-submit');    }  

Then, we can listen for events like this…

let form = document.querySelector('ajax-form');  form.addEventListener('ajax-form:before-submit', function (event) {  	// Do stuff...  });  

Or, you can use event delegation to listen for events on all <ajax-form> elements…

document.addEventListener('ajax-form:before-submit', function (event) {  	// Do stuff...  });  

Some details…

We're probably submitting our form asynchronously, so we probably need to add the async operator to handleEvent(), and await when we fetch() form data

/**   * Handle submit events   * @param  {Event} event The event object   */  async handleEvent (event) {    	// Emit an event before submitting the form  	this.emit('before-submit');    	// Emit an event while submitting the form  	this.emit('submit');    	// Do stuff with the form...  	let request = await fetch(this.form.action, {});  	let response = await request.json();    	// Emit an event after submitting the form  	this.emit('after-submit');    }  

We probably also need to actually get the form field data. We might do that first, and pass it along as the detail for the events.

We might also pass along the response to the after-submit event.

/**   * Handle submit events   * @param  {Event} event The event object   */  async handleEvent (event) {    	// Get the form data  	let data = Object.fromEntries(new FormData(this.form));    	// Emit an event before submitting the form  	this.emit('before-submit', data);    	// Emit an event while submitting the form  	this.emit('submit', data);    	// Do stuff with the form...  	let request = await fetch(this.form.action, {  		method: this.form.method,  		headers: {  			'Content-type': 'application/json'  		},  		body: JSON.stringify(data)  	});  	let response = await request.json();    	// Emit an event after submitting the form  	this.emit('after-submit', {  		fields: data,  		response  	});    }  

Cancelling the event

One fun thing you can do with custom events is cancel stuff from running using the event.preventDefault() method.

For example, let's imagine that we wanted to check for the value of the [name="answer"] field in our form, and only submit the form if it's equal to 42.

let form = document.querySelector('ajax-form');  form.addEventListener('ajax-form:before-submit', function (event) {  	if (event.detail.answer !== '42') {  		event.preventDefault();  	}  });  

If your custom event has the cancelable option set to true (ours does), you can use the Event.preventDefault() method to cancel it.

The Element.dispatchEvent() method returns false if the event was canceled, and true if it was not.

Inside out handleEvent() method, we can check if our before-submit event returns false. If it does, we'll use the return operator to bail early.

/**   * Handle submit events   * @param  {Event} event The event object   */  async handleEvent (event) {    	// Get the form data  	let data = Object.fromEntries(new FormData(this.form));    	// Emit an event before submitting the form  	let canceled = !this.emit('before-submit', data);  	if (canceled) return;    	// Emit an event while submitting the form  	this.emit('submit', data);    	// Do stuff with the form...  	let request = await fetch(this.form.action, {  		method: this.form.method,  		headers: {  			'Content-type': 'application/json'  		},  		body: JSON.stringify(data)  	});  	let response = await request.json();    	// Emit an event after submitting the form  	this.emit('after-submit', {  		fields: data,  		response  	});    }  

Wrapping up

If you need or want to extend your Web Component, custom events provide a modern, flexible way to do that works better than callback methods.

Cheers,
Chris

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

Share :

Facebook Twitter Google+
0 Komentar untuk "[Go Make Things] Callbacks on Web Components?"

Back To Top