FormHosting: How to restore HostPanel to its original state?

I have successfully implemented FormHosting according to your sample application:

procedure TFrmMain.btCreateSubF2Click(Sender: TObject);
  // destroy possible old form
  if Assigned(frm) 
     then frm.Close;
  frm :=  TSubForm2.CreateNew(HostPanel.ElementID, nil);
  btTransferGet.Enabled := false;
  btTransferSet.Enabled := false;

However, after removing the hosted form I would like to see my original HostPanel again with all its components. I can't seem to find a solution...

Thanks again for your great work!
and help!

This will change what is inside your HostPanel and that cannot be restored.

Do not contain both forms in the same hostpanel. If you want your previous form restored (with state) just hide it before creating your SubForm2 and unhide it in the close event of SubForm2.

Show/Hide/Close on a web form works very different from regular VCL forms. You will find long discussions about that in the forum. For me, the best way to come as close to Delphi VCL forms as possible is the following approach.

If MainForm.html ist the html file of your main form, then for each additional form you use in your app, create an individual <div> in your MainForm.html, like so:

<div id="ContentForm1"></div>
<div id="ContentForm2"></div>
<div id="ContentForm3"></div>

Then, during initialisation, create all your forms and put them in individual <div> containers. Take care though as form creation is an async process. Before creating the next form, the previous form has to be finished its creation or else you will receive mixed HTML-salad! So, DO NOT JUST DO THIS:

Form1 :=  TForm1.CreateNew('ContentForm1', nil);
Form2 :=  TForm2.CreateNew('ContentForm2', nil);
Form3 :=  TForm3.CreateNew('ContentForm3', nil);

Instead, sync it using this aproach:

Type TThenProc = Reference to Procedure (JV : JSValue = Nil);

Procedure TMainForm.CreateSubform(FormNo : Integer; AfterAllFormsCreated : TThenProc);

  Procedure OnFormCreated(AForm: TObject);
   TWebForm(NewForm).Visible := False;

 // Caution: Recursive
 Case FormNo of
   1 : Form1 := TForm1.CreateNew('ContentForm'+IntToStr(FormNo),@OnFormCreated);
   2 : Form2 := TForm2.CreateNew('ContentForm'+IntToStr(FormNo),@OnFormCreated);
   3 : Form3 := TForm3.CreateNew('ContentForm'+IntToStr(FormNo),@OnFormCreated);
   4 : AfterAllFormsCreated;

Somewhere during application initialization:

   Procedure(ASuccess, AFailed: TJSPromiseResolver)
     CreateSubform(1,Procedure (JV : JSValue)

Now, use FormXYZ.Visible to show or hide individual forms, like you would do in VCL. In fact, setting Form.Visible changes the "display" style attribute of the <div> that hosts the form!

At least, this works well for me after days of fiddling with this problem...

1 Like

There's an example of something similar, where forms are swapped in and out of a div as needed, may be of interest. Lots of other things in this thread as well.

Interesting reading as well, Andrew. And it again shows that handling multiple forms is not trivial at all in TMS Web. With my approach though I have tried to implement form creation and usage as close to the well known VCL style as possible. Create them once and use as often as you need, without losing form content in between. Maybe it's worth adding to the sticky as well?

I have decided to use two panels on my MainForm.
It works well and is easy to implement.

   if ItemIndex>0 then begin
   case ItemIndex of
    0: // Home
      panelMain.visible := true;
      panelHost.visible := false;
    1: // PatData
      webForm :=  Tfpat.CreateNew(panelHost.ElementID, nil);
1 Like

What I like about TMS Web Core is all the flexibility it brings. I'm an ancient developer (Turbo Pascal!) so I appreciate VCL-minded approaches, but I also realize than an HTML page is a different beast entirely, so other approaches may be more interesting. Many things become trivial... ...once you know about them!

Glad you've got something that works well for your situation. There are always tradeoffs when it comes to deciding when to create forms, when to display them, whether their contents need to be retained, and so on. So if a similar situation arises again, keep in mind there are many approaches possible depending on your specific mix of requirements.

If you were wanting to add something to the sticky thread, maybe add a "form management" post that gives a quick overview and then references this thread, the other thread I mentioned and any other support center threads (or other resources - like the docs perhaps) that you think were helpful in coming up with a workable implementation for the various use-cases we've seen? Naturally people will be looking at different approaches so no one way stands out to me as the best way.

Totally agree, Andrew, but as an ancient developer (UCSD Pascal on PDP-11/Apple II, 1:0 for me I guess ;-)), for me it's just that the main reason for using TMS Web Core, as most likely for most users, is that it is advertized as being very close to the Delphi/VCL RAD approach. Or else I could just use one of the countless JS toolchains. Therefore I'm always looking for concepts to make a transition to Web Core for me and my other (ancient) Delphi developers in the team as easy as possible. In particular when it comes to "transpile" existing VCL desktop programs to the web as quick and cost effective as possible. One major problem to achieve this goal was/is the async-ness of the underlying JS, which breaks a lot of existing VCL code. One example of which is the async form creation issue discussed here. So I'm always looking for ways to "asyncawaitify" those problematic areas for my developers so they can focus on other tasks.

1 Like

All good! I make no claim over managing the sticky post, just the person who started it. If you (or anyone else) has ideas that help that group of users (migrating VCL developers in particular) I'm sure we'll all appreciate it.