-
Notifications
You must be signed in to change notification settings - Fork 9
How to make Component event design?
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 useComponentEvent
.
: 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.
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
.
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
});
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
.
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.