TForm.Execute destroys HTML of form

Still struggling with synced form creation and usage.

I'm doing this to sync create a form in a container:

On Mainform loading I do:

LoginForm := TLoginForm.CreateNew('Container1'),nil);
Await(TLoginForm,LoginForm.Load());

On the login form, I have

Procedure TLoginForm.BtnRegisterClick(Sender: TObject);
Begin
  ModalResult := mrAbort;
End;

Somewhere in the code I do:

LoginForm.Visible := True;
MR := Await(TModalResult,LoginForm.Execute);

This all works, except the fact that when returning from Execute the HTML of the form has disappeared from the DOM, read, the <div id='Container1'> is empty afterwards.

Why is that and how can I prevent this from happening?

Thanks alot,

Walter

The forml HTML is after Execute indeed removed.
You still need it somehow?

I use a scheme where the login form loads full screen when you first access the app. Once the app is running the login form is still full screen, but a modal popup.

That's not the safest data wise (still working on that) but it does preserve the background form - saves a lot of client shouting if they are half way through their data entry and the JWT times out.

Hello Bruno,

yes, indeed, I traced it down to the fact that setting the forms ModalResult calls Close which does Container.innerHTML;=''. So this clarifies the behaviour.

Why do I need the HTML? It's not in particular the HTML, it's the TForm instance as a whole that I reuse all over again. On initialization, I create all my forms into respective containers. Then when I need to switch forms I just switch the forms Visible property. One nice aspect is that this approach, once the app has loaded all forms, makes the app "snappier". But the main aspect is that my TForm instances are not getting destroyed which would lead to loosing all data of the form. And this is also much more conforming to the regular way Delphi handles forms. This particular discussion is something we already had a year ago.

Meanwhile, I found a workaround which I will post later.

As always, thanks Bruno for the support!

Here is my workaround to execute a form in a modal (synced) way without loosing the HTML or the form itself on return:

I have:

TBaseForm = class(TWebForm)
  Private
    FSyncResultProc : TModalResultProc;
    FSyncResult : TModalResult;
    Procedure SetSyncResult(Value : TModalResult);
  Public
    Property SyncResult : TModalResult read FSyncResult write SetSyncResult;
    [async]
    Function SyncExec : TModalResult;

{---------------------------------------}

Procedure TBaseForm.SetSyncResult(Value: TModalResult);
Begin
 If Value=FSyncResult then exit;

 FSyncResult := Value;
 If Value=mrNone then exit;

 If assigned(FSyncResultProc) then
  Begin
   FSyncResultProc(Value);
   FSyncResultProc := Nil;
  End;
End;

{---------------------------------------}

Function TBaseForm.SyncExec: TModalResult;
Begin
 Result := Await(TModalResult,TJSPromise.new(
  Procedure(ASuccess, AFailed: TJSPromiseResolver)
   Begin
    FSyncResultProc := Procedure(AValue: TModalResult)
     Begin
      ASuccess(AValue);
     End;
   End
 ));
End;

{---------------------------------------}

TLoginForm = Class(TBaseForm)
...

On application initialization I do:

LoginForm := TLoginForm.CreateNew('Container1'),nil);
Await(TLoginForm,LoginForm.Load());

On the TLoginForm I have

Procedure TLoginForm.BtnRegisterClick(Sender: TObject);
Begin
   SyncResult := mrAbort; // mrOk, mrYes or whatever
End;

Somewhere in the code I do:

Var MR : TModalResult;

LoginForm.Visible := True;
MR := Await(TModalResult,LoginForm.SyncExec);
LoginForm.Visible := False;

someotherform.Visible := True;

One more word on the nasty very quickly growing async/await cascades by means of a feature request to the pas2js guys:

In the scenario above, the compiler knows that SyncExex is declared [async]. It shouldn't be too complicated for the compiler to also internally "asyncawaitify" all functions calling SyncExec.I see no point in letting the user choose wheather or not to call an [async] flagged function synchronized using await() or not. Why would I ever want to call an [async] flagged function NOT in a synced way?