I'm working on a project where I need to create an object in an iframe and then send said object to the parent window.
The problem is the postMessage
is failing as the object cannot be cloned (DataCloneError
) as it has a function (callback
) property.
What further complicates this is there is a cyclic relationship whereby button lists contain buttons and each button has a reference to its parent list.
If this was using JSON.stringify
rather than structured cloning, one could override toJSON
on the button and avoid sending callback
and replace list
with listId
to avoid the cyclic reference situation. Is there an equivalent to toJSON
for structured cloning which would allow ignoring callback
while maintaining a cyclic relationship, or another solution?
This is the rough gist of the situation with the error reproducable:
class ButtonList {
constructor() {
this.buttons = [];
}
addButton(button) {
if (!this.buttons.includes(button)) {
this.buttons.push(button);
button.setList(this);
}
return this;
}
}
class Button {
setList(list) {
if (!list) return this;
if (this.list !== list) {
this.list = list;
list.addButton(this);
}
return this;
}
setCallback(callback) {
this.callback = callback;
return this;
}
getCallback() {
return this.callback;
}
runCallback() {
if (!this.callback) return this;
this.callback();
return this;
}
}
const list = new ButtonList();
const button = new Button().setList(list).setCallback(() => console.log('Hello'));
window.postMessage(list, '*');
// DataCloneError: The object could not be cloned.
The parent window does not need to know the callback but needs to know any other properties.
Create a new object with overwritten properties with
Object.assign
and send that throughpostMessage
.