RmR
RmR

Reputation: 2283

Custom Events with different trigger element and listener element

var event = new CustomEvent("custom-event", {bubbles:true, detail:"something"});
var eleA = document.getElementById("A");
var eleB = document.getElementById("B");
eleB.addEventListener("custom-event", function(e) {
    console.log("custom-event caught in element B", e.detail);
});
document.addEventListener("custom-event", function(e) {
    console.log("custom-event caught in document", e.detail);
});
eleA.dispatchEvent(event);
<html>
<body>
<div id="A">A</div>
<div id="B">B</div>
</body>
</html>

I have searched past questions but could not find an answer. I have an element A that triggers a custom event and would like another element B to receive the event and act on it. for example:

var event = new CustomEvent("new-event");
var eleA = document.querySelector("#A");
eleA.dispatchEvent(event);

//...
// somewhere else
...
var eleB = document.querySelector("#B");
eleB.addEventListener("new-event", function(e) {
   console.log('heard');
});

I find that the event is not triggered. I tried adding:

var event = new CustomEvent("new-event", {bubbles:true});

but no difference, but however, if I change the listener to as below it works:

document.addEventListener("new-event", function(e) {
   console.log('heard in document');
});

Is it because of some propagation issue? Isn't there a way I can only listen for it in one or more specific elements?

Upvotes: 2

Views: 2346

Answers (1)

Ele
Ele

Reputation: 33726

You're confusing the use of dispatchEvent function.

.dispatchEvent()

Dispatches an Event at the specified EventTarget, invoking the affected EventListeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().


A custom event is dispatched to the listeners of a specific target object. It is not dispatched to all listeners of that event no matter which object the event is dispatched to or which object is being listened to? It basically works exactly like a 'click' event works. The event is dispatched only to a specific object and only the listeners for that event attached to that specific object. Reference

The events will be dispatched using the context of an element and every element listening to that specific event will receive the notification. So, you're not attaching

The notification will be received through the used callbacks in addEventListener() function.

This code snippet shows how elementA, elementB, and document are listening to the same new-event event:

var event = new CustomEvent("new-event");
var eleA = document.querySelector("#A");

eleA.addEventListener("new-event", function(e) {
  console.log('new-event from Element A');
});

eleA.dispatchEvent(event);

var eleB = document.querySelector("#B");
eleB.addEventListener("new-event", function(e) {
  console.log('new-event from Element B');
});

eleB.dispatchEvent(event);

document.addEventListener("new-event", function(e) {
  console.log('heard in document');
});

document.dispatchEvent(event);
<span id='A'></span>
<span id='B'></span>

This code snippet shows how the elements listen to their own Events:

var event = new CustomEvent("new-event");
var eleA = document.querySelector("#A");

eleA.addEventListener("new-event", function(e) {
  console.log('new-event from Element A');
});

var eventB = new CustomEvent("new-eventB");
var eleB = document.querySelector("#B");
eleB.addEventListener("new-eventB", function(e) {
  console.log('new-event from Element B');
});

var eventDoc = new CustomEvent("new-eventDoc");
document.addEventListener("new-eventDoc", function(e) {
  console.log('heard in document');
});

eleA.dispatchEvent(event);
eleB.dispatchEvent(eventB);
document.dispatchEvent(eventDoc);
<span id='A'></span>
<span id='B'></span>

You can create a SharedResource object to notify an event to specific receivers.

This code snippet shows you how:

  • eleA notify to eleB and document.
  • eleC notify to eleB.

//This Object represents a shared result among receivers.
var SharedResource = function(event) {
  this.event = event;
  this.receivers = [];

  this.addReceiver = function(receiver) {
    this.receivers.push(receiver);
  }

  this.addReceivers = function(receivers) {
    this.receivers.push.apply(this.receivers, receivers);
  }

  //This function will loop over receivers array to call the current event.
  this.notify = function() {
    var $self = this;
    this.receivers.forEach(function(receiver) {
      receiver.dispatchEvent(new CustomEvent($self.event));
    });
  }
};

//Element A will send a "broadcast" message to eleB and Document.
var eleA = document.querySelector("#A");
eleA.addEventListener("click", function(e) {
  ABDocSharedResource.notify();
});

var eleB = document.querySelector("#B");
eleB.addEventListener("new-event", function(e) {
  console.log('new-event from Element B');
});

document.addEventListener("new-event", function(e) {
  console.log('new-event from Document');
});

var ABDocSharedResource = new SharedResource('new-event');
ABDocSharedResource.addReceivers([eleB, document]);

//Element C will send a "broadcast" message to eleB.
var CBSharedResource = new SharedResource('new-event');
CBSharedResource.addReceiver(eleB);

var eleC = document.querySelector("#C");
eleC.addEventListener("click", function(e) {
  CBSharedResource.notify();
});
<a href="#" id='A'>Click me! (A) - Broadcast to B and Document</a>
<br>
<a href="#" id='C'>Click me! (C) - Broadcast to B</a>


<span id='B'></span>

Upvotes: 3

Related Questions