Framework Issue with WebPage Open/Shown events

I want to use some javascript to alter some elements in the Open event.
The problem is that while the controls exist in the Open event, they don’t exist on the client’s DOM so calling control.ExecuteJavascript will always throw an exception.

Essentially:

//<-- My javascript ends up here before the control exists
new checkbox('M2gIkWCL',[]);
Xojo.controls['M2gIkWCL'].setEnabled(true);

And I need

new checkbox('M2gIkWCL',[]);
Xojo.controls['M2gIkWCL'].setEnabled(true);
//<-- I want my javascript to end up here

Because of this people usually put the Javascript in the Shown Event. There are two problems with this.

[quote]1) The shown event can fire multiple times if the control is hidden/shown again. So you need to create a custom boolean property so that your setup scripts only happen the first time
2) The controls are shown in the client’s browser BEFORE this event fires, meaning any changes I do will have a lag and then a second later all the updates will apply. This quite frankly is horribly unprofessional and unacceptable from a user experience standpoint.[/quote]

Do we need some new Event like OpenComplete() where we can add this javascript?
(I know C# gives you PageLoad and PageLoad_Complete events to handle this exact scenario when using WebForms)
Does someone know a good way to hack around this?

Checking for user defined flags is the only way I know…Maybe PageSource with the “After Content” option instead of “before content”? Will play around here to see what works and what doesn’t…

[quote=190187:@Brock Nash]I want to use some javascript to alter some elements in the Open event.
The problem is that while the controls exist in the Open event, they don’t exist on the client’s DOM so calling control.ExecuteJavascript will always throw an exception. Do we need some new Event like OpenComplete() where we can add this javascript?
(I know C# gives you PageLoad and PageLoad_Complete events to handle this exact scenario when using WebForms)
Does someone know a good way to hack around this?[/quote]

It is not necessarily a question of control existing.

This code in Open triggers “Could not execute returned javascript: Cannot read property ‘setStyle’ of undefined”

dim exe as string = "x = document.getElementById('"+Label1.ControlID+"') ; alert(x.innerHTML); " self.ExecuteJavaScript(exe)

Amazingly, the very same code in a timer with period 1 started in Open displays the MsgBox just fine.

I suspect the control is created the instant the Open event ends.

Feedback number?

The WebControls objects are created in XOJO
Then the Open Event Runs
Then the Javascript to Render the WebControls is sent to browser.

When you use the “executeJavascript” event in the Open event, the javascript is put “Above” the javascript that is being sent to render the controls. Therefor the controls don’t exist and the exception is thrown.

But putting logic in the Shown event is too late and too slow (likewise with a timer). I need a way to send javascript at the END of the Open event.

[quote=190220:@Brock Nash]The WebControls objects are created in XOJO
Then the Open Event Runs
Then the Javascript to Render the WebControls is sent to browser.

When you use the “executeJavascript” event in the Open event, the javascript is put “Above” the javascript that is being sent to render the controls. Therefor the controls don’t exist and the exception is thrown.

But putting logic in the Shown event is too late and too slow (likewise with a timer). I need a way to send javascript at the END of the Open event.[/quote]

That is exactly what happens with a 1 or 0 millisecond timer started in the Open event. Action fires the instant Open ends.

The delay for the timer is too long. On my Mac OSX and Chrome, you see the layout for a period of time before everything snaps into position. This delay will be even worse when deployed.

I think I got it. WebTimer is a client side one, so it can never be faster than shown.

I have placed a Timair as Timer (the server side one) on the webpage, and this code :

Sub Open() dejamic = Microseconds Timair = new Timer AddHandler Timair.Action, addressof TimairAction Timair.mode = Timer.ModeSingle Timair.Period = 0 Timer1.enabled = True End Sub

dejamic is a double added to the webpage

[code]Sub TimairAction(sender as timer)
System.DebugLog "Timair “+str((Microseconds-dejamic)/1000)
dim exe as string = “x = document.getElementById(’”+Label1.ControlID+”’) ; alert(x.innerHTML); "
self.ExecuteJavaScript(exe)
Timair.enabled = False
End Sub

Sub Shown()
System.DebugLog "shown "+str((Microseconds-dejamic)/1000)
End Sub[/code]

Execution time seems to vary with sessions, but the timer does fire consistently before shown

First time Second third Timair = 9.92 = 19.4135 = 20.824 Shown = 218.259 = 44.2929 = 44.3189

Execution times stabilize after a couple page refresh.

Even the first one, JavaScript executes flawlessly 9.92 milliseconds after Open.

Thanks @Michel Bujardet

I didn’t think to use an actual timer over a webtimer. That did the trick. But it is a bit annoying that I have to include this on every page. I’ll subclass the timer and add an extension method for WebView to make my life easier.

me.ExecuteDelayedJavaScript()

Hmm I’m still noticing a short delay before all the components get in their proper location. There definitely should still be a fix to the framework for this.

I also noticed that unless I set the WebView to have a timer property, the timer goes out of scope before it executes. Is there an easy way to keep this in memory without having to add this to the WebView and have it cleaned up after executing?

<https://xojo.com/issue/39490>

Use a module property ?