Skip to content

How to make Component event design?

YongWoo Jeon edited this page Mar 4, 2021 · 8 revisions

Component Event Rule

Component Event naming conventions were created to make components similar to components when creating components, creating components for users to use components without recharging them.The basic concept was based on the DOM events in W3C, adding the experience we built.

The stop method of event is not supported by default since v3. Please refer to link and use ComponentEvent.

beforeXXX And XXX Event

Separate two events.

: In some cases, when an event is created, the event must occur after the function has been activated, and in some cases the event must occur before proceeding. For example, Suppose we make a checkbox component. And Checkbox has change event. Change events are events that occur after being changed from [] to [V].Change events usually change the status of the changed state to the server, as shown below.

const checkbox = new CheckBox("#id");
checkbox.on("change", ({type})  => {
	fetch("/change",{
		body: JSON.stringify({type})
	}).then( e => {
		console.log("success");
	});
});

eg.Component However, if you need to handle the logic of change event after confirming a certain condition before changing from [] to [V], you can handle it in change event as below.

checkbox.on("change", ({type})  => {
	if( condition ){
		fetch("/change",{
			body: JSON.stringify({type})
		}).then( e => {
			console.log("success");
		});
	} else {
		// Logic to change to [V] -> []
	}
});

However, since the change event has already been changed from [] to [V], the logic to be passed back from [V] to []should be added. So change the change event to an event that occurs before the change from[]to[V]. Then the logic to return is no longer needed Of course, unlike the initial logic, you have to think that it has changed since it was before the state changed.

checkbox.on("change", ({type})  => {
	if( condition ){
		type = type == 1 ? 2 : 1; // It has not changed yet and must be changed from 1 to 2.
		fetch("/change",{
			body: JSON.stringify({type})
		}).then( e => {
			console.log("success");
		});
	}
});

Next, I created a FileUpload component. The component has a upload event that occurs when the file is uploaded.

const fileUpload = new FileUpolad("#id");
fileUpload.on("upload", {files}  => {
	notifier(`${getFileCount(files)} file(s) uploaded`);
});

In this way, the change event of the Checkbox and the upload event of the FileUpload are events that occur after the action (upload of the file) ends or before the action finishes (change of the checkbox) I can not tell. So, events that occur before the end of the action so that the user can distinguish between the event that occurred after the action (upload) and the event before the action (change), use before prefix .

The beforeXXX event provided by the egjs component is an event that occurs before the action occurs, and XXX is an event that occurs after the action ends. For example, beforeFlickStart is an event that runs before the flickStart event starts. Flick is an event that occurs when the action flick is over. The general event name is easy to understand if you think it works with the after prefix.

Also, beforeXXX and XXX may exist only on one side of a component, but a beforeXXX event should always be ready to create an XXX event. That is, in the beforeXXX event, we should stop the action with the stop() method.

Both events are synchronous and can be stopped with stop().

beforeXXX occurs by default before the action takes place and XXX occurs after the action. Let's make the example in the more precise way. Checkbox must determine whether to change the condition clause before the action runs. If so, you can do so by using the stop() method as shown below.

const checkbox = new CheckBox("#id");
checkbox.on("beforeChange", ({stop})  => {
	if( !condition ){
		stop();
		// If you do `stop ()`, do not change `Checkbox` to [] -> [V].
		// Since the state has not changed, the change event also does not occur.
	}
});
checkbox.on("change", ({type})  => {
	fetch("/change",{
		body: JSON.stringify({type})
	}).then( e => {
		console.log("success");
	});
});

The components of egjs are inherited from eg.Component. The component thus created will dispatch a custom Event object as the first argument to the event listener registered when the event is fired. Custom event objects have a special stop() method. If you use the stop() method, you should make sure that the behavior inside the component does not work ([] -> [V], or upload the file ..). Therefore, if you use stop(), the XXX event does not occur.

beforeXXX and XXX occur in order, and beforeXXX can use the stop() method to stop XXX. XXX can also use the stop() method, but it does not affect the behavior since it has already been done.

Component developers must think that users can use the stop() event when creating beforeXXX.

XXXStart and XXXEnd Event

Events with start and end are made of XXXStart ~ XXXEnd.

Sometimes there is a single action, like change or upload, but there are cases where you need to generate an event that starts and ends. In this case, use postfix as XXXStart for starting events, and use postfix as XXXEnd for ending events. For example, suppose you want to create a start, middle, and end event for an animation to work. If so, it will be created with animationStart,animationInterval, and animationEnd.

const animation = new SuperAnimation("#id");
animation.on("animationStart", (e)  => {
 	// animation Start
});
animation.on("animationEnd", (e)  => {
 	// animation End
});

The beforeXXX and XXstart events are not relevant.

If you create the previous rule, the relationship between beforeXXX and XXXStart becomes ambiguous. For example, suppose you create a Drag component.

const drag = new Drag("#id");
drag.on("dragStart", (e)  => {
 	// drag start
});
drag.on("drag", (e)  => {
 	// drag ing
});
drag.on("dragEnd", (e)  => {
 	// drag end
});

I created an event that causes dragStart to start at drag, drag at drag, and dragEnd at completion. Suppose you want to disable drag before the default drag occurs, similar to the Checkbox above. Then, if you run e.stop () at the dragStart time, it feels like drag should not start, but it is not. dragStart is an event that occurs after the basic action of dragStart has already been executed, and it is not related to drag. If you want to stop drag, then it is a rule to stop drag with e.stop () by creating beforeDrag which stops the basic action of drag rather than dragStart.

const drag = new Drag("#id");
drag.on("dragStart", (e)  => {
 	// drag start
});
drag.on("beforeDrag", ({stop})  => {
 	// drag before
	stop();
});
drag.on("drag", (e)  => {
 	// drag ing
});
animation.on("dragEnd", (e)  => {
 	// drag end
});

In short, if you think that the XXX (dragStart, drag, dragEnd) that occurs after the basic action has already worked does not affect the stop() of the custom event object directly do. The event that affects the basic action is beforeXXX.

It can indirectly affect the default action between the XXXStart event and the XXXEnd.

If you write in the previous rule, you have another question. If you stop the drag at the beforeDrag time, as in the example above, does dragEnd have to happen? Should not it happen? I tried to define this part as a rule, but there are cases where XXXEnd should always occur for each component,XXXEnd does not occur, or XXXAbort is treated differently. And this case may change as the component is released. So, the rules are not directly affected, but the case that indirectly affects through beforeXXX should be left to the discretion of the component developer.

Let's take an example of the Drag component above.

const drag = new Drag("#id");
drag.on("dragStart", ({target})  => {
 	// drag start
	target.classList.add("selected"); // At start, Add selected class
});
drag.on("beforeDrag", ({target, stop})  => {
 	// Just before the drag
	if( target.classList.contain("disabled"){ // At start, if it has disabled class that stop
		stop();  
	}
	
});
drag.on("dragEnd", ({target})  => { // At end, Remove selected class
 	// drag end
	e.target.classList.remove("selected");
});

When I make it like this, it seems to be appropriate for the Drag component to cause dragEnd to occur even if I stop beforeDrag.

const file = new FileUpload("#id");
file.on("uploadStart", ({target})  => {
 	// file validate
});
file.on("uploadProgress", ({target, stop})  => {
	// file uploading
	stop();
});
file.on("uploadEnd", ({target})  => {
 	// completed
	e.target.classList.remove("selected");
});
file.on("uploadAbort", ({target})  => {
 	// abort
	e.target.classList.add("abort");
});

In the above case, it is appropriate to deal with uploadAbort instead of uploadEnd. So it was difficult to make such a uniform rule, so the developer decided to worry and decide.