Create Custom Event

let event = new Event(event_type [, options]);

Here, event_type is the name of the event and must not match with any predefined events.

The argument options is an object. Which has only two properties. One is bubbles and last is cancelable. If bubble is true, then the event bubbles upto the topmost element. By default it is false. If cancelable property is set to true, then the “default action” may be prevented.

let event = new Event("notified", {
	bubble : true,
	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 built-in event. If the event was created with the bubbles flag, then it bubbles.

Here is an example -

<button onclick="startEvent1()" id="button1">Car</button>
<script type="text/javascript">
	button1.addEventListener("purchase", function(event){
		alert("Thank you for purchasing "+ event.target.textContent);
		alert("Trusted Event = " + event.isTrusted);
	});
	function startEvent1(){
		// Do other stuff --
		alert("Creating Event and Dispatching");
		var event = new Event('purchase');
		button1.dispatchEvent(event);
	}
</script>

There are few things you should remember when you are using custom events -

Event.isTrusted

Event can be occured in two ways -

If an event is generated by some output devices then the property isTrusted is true. And if the event is generated by some script, then the property isTrusted is false.

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:

<button id="button2">Bubble Effect</button>
<script>
  // catch on document...
  document.addEventListener("hello", function(event) { // (1)
    alert("Hello from " + event.target.tagName); // Hello from H1
  });
  button2.onclick = function(event){
  	// ...dispatch on elem!
	  let event1 = new Event("hello", {bubbles: true}); // (2)
	  button2.dispatchEvent(event1);
  };
</script>

Dispatching In-Built Events

If you want to create a inbuilt event and dispatch it you should use the specific class for specific event instead of using Event class. For example, if you want to create an event that is generated by mouse click, you can use inbuilt event MouseEvent class instead of Event class. The right constructor allows to specify standard properties for that type of event. Here is an example -

let event = new MouseEvent("click", {
  bubbles: true,
  cancelable: true,
  clientX: 100,
  clientY: 100
});

alert(event.clientX); // 100

Here we can add more properties that are only acceptable by MouseEvent class. If you used Event class, it wouldn't work -

let event = new Event("click", {
  bubbles: true, // only bubbles and cancelable
  cancelable: true, // work in the Event constructor
  clientX: 100,
  clientY: 100
});

alert(event.clientX); // undefined, the unknown property is ignored!

Technically, we can work around that by assigning directly event.clientX=100 after creation. But still, using the proper type of the event class is the standard way.

CustomEvent

If you want to create a custom event, you can use CustomEvent class instead of Event class. Technically CustomEvent is the same as Event, with one exception.

In the second argument (object) we can add an additional property detail for any custom information that we want to pass with the event.

<h1 id="elem">Hello for John!</h1>

<script>
  // additional details come with the event to the handler
  elem.addEventListener("hello", function(event) {
    alert(event.detail.name);
  });

  elem.dispatchEvent(new CustomEvent("hello", {
    detail: { name: "John" }
  });
</script>

The detail property can have any data. Technically we could live without, because we can assign any properties into a regular new Event object after its creation. But CustomEvent provides the special detail field for it to evade conflicts with other event properties.

The event class tells something about “what kind of event” it is, and if the event is custom, then we should use CustomEvent just to be clear about what it is.

event.preventDefault()

We can call event.preventDefault() on a script-generated event if cancelable:true flag is specified.

Of course, if the event has a non-standard name, then it’s not known to the browser, and there’s no “default browser action” for it. But the event-generating code may plan some actions after dispatchEvent. The call of event.preventDefault() is a way for the handler to send a signal that those actions shouldn’t be performed. In that case the call to elem.dispatchEvent(event) returns false. And the event-generating code knows that the processing shouldn’t continue.

In the following example, there’s a hide() function. It generates the "hide" event on the element #rabbit, notifying all interested parties that the rabbit is going to hide. A handler set by rabbit.addEventListener('hide',...) will learn about that and, if it wants, can prevent that action by calling event.preventDefault(). Then the rabbit won’t hide:

<pre id="rabbit">
  |\   /|
   \|_|/
   /. .\
  =\_Y_/=
   {>o<}
</pre>

<script>
  // hide() will be called automatically in 2 seconds
  function hide() {
    let event = new CustomEvent("hide", {
      cancelable: true // without that flag preventDefault doesn't work
    });
    if (!rabbit.dispatchEvent(event)) {
      alert('the action was prevented by a handler');
    } else {
      rabbit.hidden = true;
    }
  }

  rabbit.addEventListener('hide', function(event) {
    if (confirm("Call preventDefault?")) {
      event.preventDefault();
    }
  });

  // hide in 2 seconds
  setTimeout(hide, 2000);

</script>

Nested Event, Events, All are Synchronous

Events are processed synchronously. It means Javascript wait for one event to complete to start another one. If you dispatch an event within another event then the control jumps into the nested event and when the nested event is completely fully processed, then the controll goes back to calling handler and continue executing.

	<button id="button4">Click</button>
	<script type="text/javascript">
		button4.addEventListener("check",function(){
			console.log("Nested - Start");
			var i = 0;
			while(i<100){
				i++;
				console.log(i);
			}
			console.log("Nested - End");
		});
		button4.onclick=function(event){
			console.log("Outer - Start");
			console.log("Start Dispatching");
			var event2 = new CustomEvent("check");
			button4.dispatchEvent(event2);
			console.log("End Dispatching");
			console.log("Outer - End");
		};
	</script>

Here is another example -

<button id="button5">Click</button>
<script type="text/javascript">
button5.onclick=function(){
	var i = 0;
	while(i<10000000){
		i++;
	}
	console.log("Inside the Handler");
};
console.log("Start Dispatching");
var event3 = new MouseEvent("click");
button5.dispatchEvent(event3);
console.log("Outside the Handler");
</script>