# Dispatching custom events We can not only assign handlers, but also generate events from JavaScript. Custom events can be used to create "graphical components". For instance, a root element of our own JS-based menu may trigger events telling what happens with the menu: `open` (menu open), `select` (an item is selected) and so on. Another code may listen to the events and observe what's happening with the menu. We can generate not only completely new events, that we invent for our own purposes, but also built-in ones, such as `click`, `mousedown` etc. That may be helpful for automated testing. ## Event constructor Build-in event classes form a hierarchy, similar to DOM element classes. The root is the built-in [Event](http://www.w3.org/TR/dom/#event) class. We can create `Event` objects like this: ```js let event = new Event(type[, options]); ``` Arguments: - *type* -- event type, a string like `"click"` or our own like `"my-event"`. - *options* -- the object with two optional properties: - `bubbles: true/false` -- if `true`, then the event bubbles. - `cancelable: true/false` -- if `true`, then the "default action" may be prevented. Later we'll see what it means for custom events. By default both are false: `{bubbles: false, cancelable: false}`. ## dispatchEvent After an event object is created, we should "run" it on an element using the call `elem.dispatchEvent(event)`. Then handlers react on it as if it were a regular browser event. If the event was created with the `bubbles` flag, then it bubbles. In the example below the `click` event is initiated in JavaScript. The handler works same way as if the button was clicked: ```html run no-beautify ``` ```smart header="event.isTrusted" There is a way to tell a "real" user event from a script-generated one. The property `event.isTrusted` is `true` for events that come from real user actions and `false` for script-generated events. ``` ## Bubbling example We can create a bubbling event with the name `"hello"` and catch it on `document`. All we need is to set `bubbles` to `true`: ```html run no-beautify
|\ /| \|_|/ /. .\ =\_Y_/= {>o<}``` Обратите внимание: событие должно иметь флаг `cancelable: true`, иначе вызов `event.preventDefault()` будет проигнорирован. ## Events-in-events are synchronous Usually events are processed asynchronously. That is: if the browser is processing `onclick` and in the process a new event occurs, then it awaits till `onclick` processing is finished. The exception is when one event is initiated from within another one. Then the control jumps to the nested event handler, and after it goes back. For instance, here the nested `menu-open` event is processed synchronously, during the `onclick`: ```html run autorun ``` The output order is: 1 -> nested -> 2. Please note that the nested event `menu-open` fully bubbles up and is handled on the `document`. The propagation and handling of the nested event must be fully finished before the processing gets back to the outer code (`onclick`). That's not only about `dispatchEvent`, there are other cases. JavaScript in an event handler can call methods that lead to other events -- they are too processed synchronously. If we don't like it, we can either put the `dispatchEvent` (or other event-triggering call) at the end of `onclick` or, maybe better, wrap it in zero-delay `setTimeout`: ```html run ``` Now `dispatchEvent` runs asynchronously after the current code execution is finished, including `mouse.onclick`, so event handlers are totally separate. The output order becomes: 1 -> 2 -> nested. ## Summary To generate an event from code, we first need to create an event object. The generic `Event(name, options)` constructor accepts an arbitrary event name and the `options` object with two properties: - `bubbles: true` if the event should bubble. - `cancelable: true` if the `event.preventDefault()` should work. Other constructors of native events like `MouseEvent`, `KeyboardEvent` and so on accept properties specific to that event type. For instance, `clientX` for mouse events. For custom events we should use `CustomEvent` constructor. It has an additional option named `detail`, we should assign the event-specific data to it. Then all handlers can access it as `event.detail`. Despite the technical possibility to generate browser events like `click` or `keydown`, we should use with the great care. We shouldn't generate browser events as it's a hacky way to run handlers. That's a bad architecture most of the time. Native events might be generated: - As a dirty hack to make 3rd-party libraries work the needed way, if they don't provide other means of interaction. - For automated testing, to "click the button" in the script and see if the interface reacts correctly. Custom events with our own names are often generated for architectural purposes, to signal what happens inside our menus, sliders, carousels etc.