29

I'm trying to propagate an event from my window.document to an iframe within this document.

When catching the event in the window.document I try the following:

event.preventDefault()
(@dispatchTo()).dispatchEvent(event)
# @dispatchTo() returns the reference of `document.querySelector('iframe').contentDocument`

But I get InvalidStateError: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.

I tried preventDefault and stopPropagation but none would work. It seems that the event is being dispatched while I try to dispatch it to the iframe document and it fails.

How can I propagate an event to my iframe while catching it from the window.document?

I do have another eventListener on the iframe for that event, but it doesn't get triggered.

I use React (which has a virtual DOM, it may interfere, it may not, just saying).


I found part-of-a-solution there: https://stackoverflow.com/a/20541207/2391795

And now I'm able to dispatch events from the document to the iframe using this code:

eventClone = new event.constructor(event.type, event)
(@dispatchTo()).dispatchEvent(eventClone)

But since I'm using React, the cloned event isn't equal to the initial event, because React has a kind-of wrapper for events. So I loose many properties, like the which and isTrusted, which become false once cloned.

Is there any way to properly clone a React event?

Community
  • 1
  • 1
Vadorequest
  • 16,593
  • 24
  • 118
  • 215
  • 4
    Possible duplicate of [How to clone or re-dispatch DOM events?](https://stackoverflow.com/questions/11974262/how-to-clone-or-re-dispatch-dom-events) – ibrahim mahrir Jun 24 '17 at 13:14
  • 1
    `isTrusted` is not part of React, it's a native browser event property. You cannot programmatically create an event and have isTrusted be `true`. – Nick May 10 '18 at 17:56

1 Answers1

14

Some event property values disappear when you try to copy the event. That's because many of the event properties have their enumerable property set to false:

Object.defineProperty(event, "target", {
    enumerable: false,
    writable: true,
});

That prevents the value of the property from being copied when you clone the event. If you tried Object.keys(evt), the only key that gets returned is isTrusted.

Some properties like target and path only get set after the event is dispatched, and you cannot assign them manually. So if you try to dispatch an event that already has a target, you will hit the error InvalidStateError: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.

That's why you hit this error. You tried to dispatch an event that already got dispatched instead of dispatching a new event.

So when you create your event, you should only copy the properties you care about:

 eventClone = new event.constructor(event.type, propertiesICareAbout) 

where propertiesICareAbout is an object containing the parts of the event you care about, for example propertiesICareAbout = {shiftKey: event.shiftKey}

isTrusted is a property with a specific purpose-- return false if a script has interacted with the event. The property is set to false for exactly that reason. You are using a script to interact with the event and dispatching it via a script. https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted

The which property is deprecated and in the process of being dropped, so you shouldn't use that anyway.

React events are probably unrelated to your question. The React synthetic event is delegated and pooled at the top level for performance reasons. If you are dispatching events manually, you should use the native browser method dispatchEvent.

Jeremy Gottfried
  • 1,061
  • 13
  • 28