CWCO logo

v1.7.9

Events

You can use event attributes to attach event listeners in the template. These attributes do not make to the DOM. They are not rendered on the elements for security reasons.

Handler Function

You can call the class function that handles that event as the attribute value.

class MyButton extends WebComponent {
	
	handleClick() {
		// logic here
	}
	
	get template() {
		return `
			<button type="button" onclick="handleClick()"></button>
		`;
	}
}

$event

You can use the $event property to pass the event to the handler when you need the reference of the event.

class MyButton extends WebComponent {
	
	handleClick(event) {
		console.log(event)
	}
	
	get template() {
		return `
			<button type="button" onclick="handleClick($event)"></button>
		`;
	}
}

Additional arguments

The $event is not the only thing you can pass to the event handler function. You can pass anything including reference to class properties by using the this keyword or any other data.

class MyButton extends WebComponent {
	
	handleClick(numb, event, type) {
		console.log(numb, event, type)
	}
	
	get template() {
		return `
			<button type="button" onclick="handleClick(12, $event, this.getAttribute('type'))"></button>
		`;
	}
}

Handler statement

Sometimes the event handler function does a very simple thing that may feel like too much to create a whole function for.

For cases like that you can simply add the logic as a handler and WebComponent will take care of creating a handler for that event listener for you.

We can simplify the above example like so.

class MyButton extends WebComponent {
	get template() {
		return `
			<button type="button" onclick="this.dispatchEvent(new Event('click'))"></button>
		`;
	}
}

You can still reference the $event this way as well.

class MyButton extends WebComponent {
	get template() {
		return `
			<button type="button" onclick="{console.log($event)}"></button>
		`;
	}
}
Note: The curly braces around everything is optional

This feature is great for small code execution. Think of inline handler as the body of the function you would otherwise create.

Dispatch Events

Dispatching events is the only way you should be passing data to parent components.

class MyButton extends WebComponent {
	get template() {
		return html`
			<input type="text" onchange="{handleChange($event)}">
		`;
	}

	handleChange(event: Event) {
		event.preventDefault();
		event.stopPropagation();

		this.dispatchEvent(new CustomEvent('change', {
			detail: event.target.value
		}))
	}
}

On the above example, we listen to a change event on the input element and then dispatch a CustomEvent of same name with the value as detail.

Best Practices

1 - Prevent default and stop propagation

Whenever you want to intercept a native event type and dispatch it with more details as the above code example, it is always good to preventDefault and stopPropagation otherwise the same event can be caught twice by the listener: 1 by your dispatch and the other by native behavior

2 - Raw data>

The way data is reactive inside the component is because it uses Proxy.

One problem that you possibly will run into is dispatching the proxied internal data which can get modified by the parent component which will trigger an update on the child component.

To fix that you should always dispatch the raw data instead of the proxied one.

import {html, WebComponent} from "cwco";

class PrentComp extends WebComponent {
   opts = [
			{value: 12, label: "one"},
			{value: 24, label: "two"},
	 ];
	
	 get template() {
			return html`<selector-dropdown options="{opts}"></selector-dropdown>`;
   }
}
import {html, raw, WebComponent} from "cwco";

class SelectorDropdown extends WebComponent {
	static observedAttributes = ['options'];
	options = [];
	
	get template() {
		return html`
			<select onchange="{handleChange($event)}">
				<option repeat="options as opt" value="{opt.value}" data-key="{$key}">{opt.label}</option>
			</select>
		`;
	}
	
	handleChange(event: Event) {
		event.preventDefault();
		event.stopPropagation();
	
		const selectedOption = event.target.selectedOptions[0];
		const optionIndex = selectedOption.dataset.key;
		
		this.dispatchEvent(new CustomEvent('change', {
			detail: raw(this.options[optionIndex])
		}))
	}
}

Simply import and call raw to get the unproxied data.