Iframe does not scale to fit embedded Anvil app

What I’m trying to do:
I want the iframe that embeds my Anvil app to fit the full content of the Anvil app, without a scroll bar.

When the content changes, the iframe size should change.

What I’ve tried and what’s not working:
I use the html proposed by Anvil:

<script src="https://anvil.works/embed.js" async></script>
<iframe style="width:100%;" data-anvil-embed src="<your app url>"></iframe>

The iframe does not scale to fit the content when the Anvil app changes, but displays a scroll bar. Tested on Crome. The website and the Anvil app are under the same domain.

Clone link:
I have reproduced the issue here: https://ornery-edible-macaw.anvil.app

Clone links:
App with the iframe: Anvil | Login

App that is embedded:
https://anvil.works/build#clone:WVOGBY6RIG3YZTTP=3BLPS7BTDW4H7HY4JCMNZQGX

Cheers,
Stein

Hello @stein
what should work is:
on the parent app, add a function to resize the iframe based on content, like (googled):

<script type="text/javascript">
  function resizeIframe() {
    frame = document.getElementById('my_iframe');
      if(frame) {
        try {
            frame.height = frame.contentWindow.document.body.scrollHeight + "px";
        } catch (exception) {
          return false;
        }
      }   
  }
</script>

On the child app, in the size-changing events, call that function:

  def check_box_2_change(self, **event_args):
    self.column_panel.visible = self.check_box_2.checked
    self.call_js('parent.resizeIframe')

  def check_box_1_change(self, **event_args):
    self.rich_text_1.visible = self.check_box_1.checked
    self.call_js('parent.resizeIframe')

  def check_box_3_change(self, **event_args):
    self.rich_text_1_copy.visible = self.check_box_3.checked
    self.call_js('parent.resizeIframe')

I tried to clone your apps and apply this, the events fire and try to access parent’s function but I hit the “cross origin” block.
If - like in your case - parent and child app share same domain then that should work for you.

BR

Thanks @aldo.ercolani !

Unfortunately, I also hit the ‘cross origin’ block. I naively thought that subdomain1.mydomain.com and subdomain2.mydomain.com were under the same domain, but they are not.

I am trying to embed the app in a Wordpress page and don’t see how I can avoid the cross origin block.

Unless someone has a solution (?), I guess I will have to live with a fixed Iframe size and scrollbars.

Stein

The solution in case of cross-domain is called Post-message.
Here’s a link, it requires a little effort to study and understand though.

With this you can safely send a message from the child iframe to the parent page and there act consequently.
The same concept, a slightly more complex implementation I guess.

What you need to do:
In the child app:

  def check_box_2_change(self, **event_args):
    self.column_panel.visible = self.check_box_2.checked
    self.call_js('notify_parent') // add this to all events that need resizing

Then in the child app’s Native Libraries:

<script>
  function notify_parent() {
    window.parent.postMessage({
      "action":"resize_iframe"
	  // add other params you need to transfer from child to parent
    },"https://ygwmwb7ehysqe2jo.anvil.app"); // Set the origin: this is to avoid cross-domain abuse. Set it to the PARENT app url
  }
</script>

This will trigger the message.
Then in the parent app’s Native Libraries:

<script type="text/javascript">
  window.addEventListener("message", (event) => {
    // Check the origin against the CHILD app url
    if (event.origin !== "https://c44iw5vxkvskiivi.anvil.app")
      return;

    if (event.data['action'] == 'resize_iframe') {
      resizeIframe();
    }
  }, false);
  
  function resizeIframe() {
    const frame = document.getElementById('my_iframe');
      if(frame) {
        try {
          // Set both since style could prevail.
            frame.height = "100%";
          	frame.style = "width:100%; height:100%;"
        } catch (exception) {
          return false;
        }
      }   
  }
</script>

And your Custom HTML Page code:

<script type="text/javascript" src="https://anvil.works/embed.js"></script>
<iframe id="my_iframe" style="width:100%;" data-anvil-embed src="https://c44iw5vxkvskiivi.anvil.app/debug/ZLMQMZKNZQ2OQO4NTQKJUYMDQK6RQ3GF%3DJLQGYZHBRM2ECVWWQWIET7K3
"></iframe>

Pay attention to set the id="my_frame" or the resizeIframe function won’t hook it.

Another thing: I preferred to simply set each time the iFrame to 100% without calculating the exact height. However, if you prefer another approach, you can calculate whatever you want on the child app, add the parameter to the dictionary and use it on the parent app at your convenience.

If you use the clone links, remeber to change appropriately the urls of parent / child used in the code.

BR

Demo of this working

Clone links
iframe_test:
https://anvil.works/build#clone:YGWMWB7EHYSQE2JO=GTUAHPUIOVFQ4E35F5YP7YW3

iframe_test_content:
https://anvil.works/build#clone:C44IW5VXKVSKIIVI=LXOEQ5E7FGJHCTZNUMPQOQNX

4 Likes

It works!

Thank you @aldo.ercolani for taking the time to write such a great answer and with working code. Much appreciated!

Cheers,
Stein

2 Likes