What I’m trying to do:
Have an Anvil app with an iframe embedding a non-Anvil page, and use the standard postMessage
technique of communicating between them. Trying to avoid reloading the iframe and using query parameters to communicate changes.
Communication from the iframe to the Anvil app is working fine, but communication from the Anvil app to the iframe is generating an error. The same code works fine in a non-Anvil page, so I assume I’m running into some restrictions based on the Anvil/Skulpt model?
What I’ve tried and is working:
Here’s what the iframe content uses to communicate with the parent app (and to prepare to receive messages, although that part isn’t working yet):
<button onclick="sendMessageToParent()">Send Message To Parent</button>
<script>
window.addEventListener("message", self.receiveMessage, false);
function sendMessageToParent()
{
console.log("sending message to parent");
window.parent.postMessage({sender: window.location.href, foo: 'bar'}, '*');
}
function receiveMessage(message)
{
console.log("Recieved in iframe");
console.log(message);
}
</script>
The message is received in the parent Anvil app just fine. Here’s the code for setting that up:
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
self.url = 'put a good URL here'
self.iframe = None
self.first_show = True
anvil.js.window.addEventListener("message", self.receiveMessage, False)
def form_show(self, **event_args):
if self.first_show:
self.iframe = anvil.js.window.document.createElement('iframe')
self.iframe.style.width = "100%"
self.iframe.style.height = "100vh"
self.iframe.setAttribute("src", self.url)
anvil.js.get_dom_node(self).appendChild(self.iframe)
self.first_show = False
def receiveMessage(self, message):
if 'sender' in message.data:
self.label_1.text = str(message.data)
All of that’s standard postMessage
handling, adapted to Anvil’s Javascript bridge, and as I say works fine.
What I’ve tried and what’s not working:
The communication back from the parent to the iframe fails, though, even though it’s using the same mechanism:
def toIFrame(self, message):
self.iframe.contentWindow.postMessage(message, '*')
def button_1_click(self, **event_args):
self.toIFrame({'data': 'something'})
The error posted in the browser logs has, among other bits, these messages:
"$mangled": "SecurityError: Failed to read a named property 'sk$object' from 'Window': Blocked a frame with origin \"https://infatuated-melodic-kinkajou.anvil.app\" from accessing a cross-origin frame.",
"$savedKeyHash": "SecurityError: Failed to read a named property 'sk$object' from 'Window': Blocked a frame with origin \"https://infatuated-melodic-kinkajou.anvil.app\" from accessing a cross-origin frame.",
"v": "SecurityError: Failed to read a named property 'sk$object' from 'Window': Blocked a frame with origin \"https://infatuated-melodic-kinkajou.anvil.app\" from accessing a cross-origin frame."
Since the same code worked outside of Anvil, how can I achieve the same effect inside of Anvil?
Clone link:
And here’s the obligatory minimal clone link for folks to play with.