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?
The dispatchEvent () method throws UNSPECIFIED_EVENT_TYPE_ERR if the event's type was not specified by initializing the event before the method was called, or if the event's type is null or an empty string.
The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent (). event is the Event object to be dispatched.
Unlike "native" events, which are fired by the DOM and invoke event handlers asynchronously via the event loop, dispatchEvent () invokes event handlers synchronously. All applicable event handlers will execute and return before the code continues on after the call to dispatchEvent ().
The event handlers run on a nested callstack; they block the caller until they complete, but exceptions do not propagate to the caller. Unlike "native" events, which are fired by the DOM and invoke event handlers asynchronously via the event loop , dispatchEvent () invokes event handlers synchronously.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With