When is self.call_js available?

I’ve got some interesting behaviour around using self.call_js

if i put it in the form show event - it can’t find the global function
If I call the python from the JS, which then calls the JS - it can’t find the global function
If I put a timer on the form and wait a couple of seconds - it CAN find the global function

Is there any way to reliably wait everything is initialized to call the javascript function?

I’ll separate out the relevant parts of my app so it is easy to reproduce.

1 Like

Yikes! That’s very odd - the script should have finished executing before the show event fires. Are you doing something odd like defining the global function in a JQuery callback?

A repro case would be excellent.

[Moving to Bug Reports]

This gets even more interesting.

Are you able to access my apps?

I’ve taken what I thought the relevant parts are into a standalone app, and it is behaving properly, but in the original app, it is not.

The app “Video Consulting” demonstrates the issue. If you

  1. run the app (
  2. register and login
  3. Click “call now” in the list
  4. A new window is opened and in the JS console you’ll see that it tries to do a fe things before “Finished loading app” appears

If you load test_call_js it loads the same scripts and same sequence of events, but all the JS invocation happens AFTER “finished loading app” appears

Perhaps it is relating to opening the app in a new window, I’ll try and add that in and see if it has an impact.

It is unrelated to the new window opening

If you go to https://test-video-conference-app.anvilapp.net/_version/dev/442362377f4efbeb/#?args={"customerId"%3A%20"[12346%2C1141843]"%2C%20"room"%3A%20"b296b160-313b-420d-a816-2f8b36431f41"%2C%20"callerType"%3A%20"client"} it will hopefully reproduce for you

image

Best thing is to PM Meredydd the clone link if you don’t want to publicly post it here.

Are you able to access my apps?

We don’t have tools for that. If you go into the Publish dialog and click “allow someone else to make a copy of my app”, you’ll see a link. Anyone with that link can take a complete copy of your app and its data.

Thanks David, I’ve sent Meredydd a message with the two links. It sure is an interesting one!


Edited because this post and the replies are not relevant to the original bug reported. I thought they were related but are not. The issue described in below about StartupForm is because it was a blank form.

Because I’ve resolved this it is no longer a blocking issue.

Hi @meredydd It’s getting even stranger now. I’m tying to do some redirections based on url hash, and am trying to call some javascript to change window.location, and now it is saying “StartupForm has no attribute call_js”

If you vist this link, it should manifest https://test-video-conference-app.anvilapp.net/#?state=aaaa&scope=read_write&code=bbbb

CLIENT: in form_show
runner.bundle.js?buildTime=1527233024:164 CLIENT: in form_show redirecting to blank
runner.bundle.js?buildTime=1527233024:164 Python exception: AttributeError: 'StartupForm' object has no attribute 'call_js'
runner.bundle.js?buildTime=1527233024:164 pt.builtin.AttributeError {args: pt.b…n.tuple, traceback: Array(1)}
runner.bundle.js?buildTime=1527233024:165 Finished loading app

This is now a blocker for me, as I can’t complete my stripe connect oauth flow because. Any help would be greatly appreciated.

If you can post/PM me the clone link for that example you give above I can take a look, but it might be tomorrow afternoon before I get the time (I might get time before lunch…)

Thanks David - I appreciate that. Do you work for Anvil? I’m happy to share the link, but I don’t want to use up community time on what looks like to be a platform issue.

But one thing you could do for me please? - if you visit that link do you get the same errors in the js console as i pasted above?

I don’t work for Anvil but I also don’t mind taking a look :slight_smile:
I like problem solving, and I use call_js a lot so I might spot what’s up.

And yes, I see the same as you do.

Thanks David - I will remember that!

And i think I have found the cause of the most recent issue (the original one at the start of this topic persists) my startup page was a “blank page” and therefore doesn’t have call_js on it, because there is not HTML and therefore no tags to have functions to call. It had been a while since I had set up that form and I forgot what type of template it was using.

Sorry for muddying the waters.

Well, I’m glad that middle issue got sorted! I’ve got your PM (those Git URLs don’t actually give me access to your app; you’ll want to open the Publish dialog and choose “Allow someone else to make a copy of my app”, then send me that URL)

@david.wylie is a (very helpful) volunteer community moderator. He also runs a business based on Anvil :slight_smile:

Update and workaround

Thanks to @phil’s help via PM, I’ve nailed down the problem. The fix is going to involve jumping through cross-browser compatibility hoops, so I’m not going to rush it. But in the meantime, here’s an explanation and a workaround:

The issue: Due to how jQuery behaves, all <script> tags in HTML forms are loaded asynchronously. This means that later scripts can execute before earlier ones have loaded. @phil was trying to load an external API in one <script> tag, and use it in the next one. Oops.

We’re modifying Anvil’s HTML handling to Do The Right Thing and execute these scripts in order, but this is dark cross-browser magic, and we’ll need a lot of testing to make sure it works everywhere. Expect this in a few days’ time.

The workaround:
In the meantime, here’s how to do it. If you add a <script> tag dynamically*, you can set an onload event handler that runs when the script has finished loading. So if we replace this:

<script src="https://meet.jit.si/external_api.js">

…with this:

<script>
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.onload = function() { /* DO SOMETHING */ }
   script.type = 'text/javascript';
   script.src = 'https://meet.jit.si/external_api.js';
   head.appendChild(script);
</script>

…now we have a function that runs when the external script has loaded!

Thanks for your patience and help getting to the bottom of this.


(* Yep - only dynamically. You might think you could write <script src="..." onload="...">, but…you can’t. Not for any good reason, I don’t think; HTML is just bonkers. That’s why we built a whole Python web app framework to save people from having to interact with it :wink: )

1 Like

Excellent work Meredydd. Those types of bugs are NOT easy to track down.

I do have a question though - the error i was getting was that the python code couldn’t even find my defined function. Yes that function would have tried to call code, but it han’t gotten there yet.

Was this because the python code wasn’t waiting until all blocks had evaluated before letting me call self.call_js()?

Was this because the python code wasn’t waiting until all blocks had evaluated before letting me call self.call_js()?

Correct! In fact, if you load an async <script> tag (which is what jQuery does), nothing gets notified when it finishes loading. (What we’re going to do is go in and effectively generate the code from my workaround behind the scenes. I’m planning a new all_scripts_loaded event for HTMLPanels, which fires when all the JS is ready, so you could trigger a call_js from that.)

Thanks for your patience while I ran this one to ground.

That is an ideal solution Meredydd, thank you! It was one i was going to suggest, so I’m glad youre going down that path :slight_smile: