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.
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?
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.
…
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 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?
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.
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
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>
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 )
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.