CustomEvent with response, is this possible?

Viewed 1005

I'm trying to incorporate a CustomEvent in my workflow. But I need this event to be a communication in both ways: a script sends the event to the document, and it should respond to the same initiator.

I've tried stuff along the lines of:

ev = new CustomEvent('StorageRequest', {
  detail: {
    space: theSpace,
    method: theMethod,
    arguments: args
  }
})
document.dispatchEvent(ev)

And my listener looks like this:

document.addEventListener('StorageRequest', (e) => {
  console.debug('Sending StorageRequest', e)
  // do something, then answer back with response
})

What's the way to achieve this?

I've tried using a Promise and sending the response using resolve/reject, but passing functions seems to break the detail in the event and it turns out to be null if I try to do that:

return new Promise((resolve, reject) => {
  ev = new CustomEvent('StorageRequest', {
    detail: {
      space: theSpace,
      method: theMethod,
      arguments: args,
      resolve, reject
    }
  })
  document.dispatchEvent(ev)
})

Notes: I'd like to avoid "generically" sending the response back to the document. I prefer the requests and responses to be fully intentional and handled within the code properly
I don't have an element attached to this, so using the element from e.target isn't an option (unless I can do something else with it)

1 Answers

You cannot "respond" in a DOM Event - they just propagate up the DOM tree until it reaches the top level.

A promise may work, setup correctly, but you would only be able to respond once. Once the promise is resolved/rejected you cannot resolve or reject it again, it will ignore subsequent resolve/reject calls.

As an alternative you can setup 2 separate events and respond to the first which should achieve what you are attempting to do:

sReqEvent = new CustomEvent('StorageRequest', {
    detail: {
    space: theSpace,
    method: theMethod,
    arguments: args
});

console.debug('Sending StorageRequest');
document.dispatchEvent(sReqEvent);

Listeners:

document.addEventListener('StorageRequest', (e) => {
    // do something, then answer back with response
    var sRespEvent = new CustomEvent('StorageResponse', e.data);
    console.debug('Sending StorageResponse', e.data);
    document.dispatchEvent(sRespEvent);
});

document.addEventListener('StorageResponse', (e) => {
    // This is my response
});

Granted this is unnecessary and you could just use a "StorageResponse" function that is called from within the StorageRequest listener...


Another alternative is to use window.postMessage, but that is more involved to setup with separate back/forth requests and IE9 will only support strings being passed (you need to JSON encode/decode the package in IE9 if you want to send anything other than a string - works, but is slower if you do it in all browsers as a global workaround).

Related