How to show a created form again?

Maybe I'm missing something pretty obvious, but I can't figure out how to show an instantiated form multiple times. In normal Delphi, once a form is created, I can hide and show it multiple times.

  • I understand Application.CreateForm() in the DPR only works on the main form. All further calls to Application.CreateForm() don't do anything, read, the forms remain uninstantiated. So all forms but the main form HAVE TO be created dynamically once they are used the first time. Did I get that right?
  • So at a certain point I create Form1 and show it within a HTML container using FormClass.CreateNew and an associated HTML ElementID. Form1 is showing fine at the desired position within the main form. Perfect.
  • In order to make Form1 disappear at a later point, I tried Form1.Hide. But the Pas2JS compiler says it does not exist. So I use Form1.Close and realize that Form1 visually disappears and still remains instantiated.
  • I CreateNew Form2, associated with the same ElementID. Form2 is also showing fine.
  • Now I want to show Form1 again, together with the data the user already entered into the edits. So I close Form2 and ... now what? Form1.Show or Form1.ShowModal don't seem to work.

What to do to show Form1 again?

Many thanks, kind regards, Walter

Try using the forms visible property. I had the same issue too. Show and Hide are not implemented.

eg

Form1.Visible := true;

HTH

Thank you for this hint, Andrew. Setting Form1.visible := false indeed makes my Form1 disappear. But unfortunately, setting Form2.visible := true doesn't make my Form2 visible. I have to say, my forms 1 and 2 live in a HTML container of a MainForm. Maybe this makes a difference (they call it "Form Hosting").

Hoping for a solution from TMS, as recreating forms all the time and keeping track of their states and contents in between, although possible, would be PITA.

Regards, Walter

Dear Bruno, may I kindly bring this back to your attention?
Many thanks!

  1. I tested with v1.6 and could not see an issue with Form.Hide
  2. Form.Close will close & remove the form resources, so it cannot be brought back as such
  3. Easiest : Form.Visible := false to hide it, Form.Visible = true to display it again. I retested this with the demo Demo\Basics\FormHosting and it worked as expected.

Dear Bruno, thank you for your response!
The FormHosting demo works because it USES close. But the point of my issue is that I do NOT want to use Close, so to not lose the form content.

If I remove the Close from the demo, the demo fails. In the first example attached I reduced the demo to the absolute necessary. The 2 subforms are only created once when they are used the first time. When then toggling between the 2 subforms I set the currently visible form to visible:=false and the other form that I wan to show to visible:=true. And exactly this does not work!
My demo does extensive logging into the console. Please have a look.
Here is what happens:

  • Click button 1 --> Subform1 will be created -> Subform1 shows OK
  • Click button 2 --> Subform1 will be set invisible and Subform2 created. --> Subform1 disappears but Subform2 does NOT show
  • Click button 1 --> Subform2 will be set invisible and Subform1 set visible --> Very strange: Subform2 shows up, while 1 was expected
  • Any further clicking on any button does not change anything to this state. Subform2 stays visible.

Formhosting toggling visible.zip (55.8 KB)

Then, based on the idea that almost anything is async, I thought that setting visible:=false maybe needs some time in order to change the DOM and therefore a delay between hiding and showing may fix the problem. But it doesn't. Result is the same. And yes, the delay is made async as well using a timer.

Formhosting Async Show.zip (56.1 KB)

Many thanks for having a look into this! I think it is a crucial issue.

Kind regards, Walter

This particular demo hosts forms alternating in the SAME panel. If you hide the form, it hides its hosting panel, hence the other form you want to show is not visible anymore because it is hosted in the same (invisible) panel.
If you want to toggle visibility on two different forms here, host these into two different panels.

The rational behind all this is that I have a HTML template from a web designer with a defined area in which to show the app content. My understanding was that I use this single <div> area, identified by its HTML id, to show the Pascal forms in. Are you telling me, that for each and every Pascal form I need an individual named HTML <div> area? And if I do so, then toggling a forms visible property actually shows/hides the individually assigned <div>? Is this how it works?
Or is there another best practice to achieve this?

Ok, I followed your advice and thought about how to best provide individual panels for each individual form. Thinking the Delphi way a PageControl would do it. So I put a TWebPageControl on the main form and link the forms to the ElementIDs of the individual pages (TWebTabSheet). When clicking a button, the respevtive Form gets created if it is not already created and ActivePage of the PageControl is set to the respective page. This works like this and works great:

type
  TFrmMain = class(TWebForm)
    btCreateSubF1: TWebButton;
    btCreateSubF2: TWebButton;
    WebLabel2: TWebLabel;
    WebLabel3: TWebLabel;
    PgCtrl: TWebPageControl;
    Page1: TWebTabSheet;
    Page2: TWebTabSheet;
    procedure btCreateSubF1Click(Sender: TObject);
    procedure btCreateSubF2Click(Sender: TObject);
...
...
procedure TFrmMain.btCreateSubF1Click(Sender: TObject);
begin
 If not assigned(SubForm1) then
  SubForm1 := TSubForm1.CreateNew(Page1.ElementID,nil);
 PgCtrl.ActivePage := Page1;
end;

procedure TFrmMain.btCreateSubF2Click(Sender: TObject);
begin
 If not assigned(SubForm2) then
  SubForm2 := TSubForm2.CreateNew(Page2.ElementID,nil);
 PgCtrl.ActivePage := Page2;
end;

Now I thought: Ok, then why not create all forms during the Create of the main form, so later on I only have to switch the pages, like this:

procedure TFrmMain.WebFormCreate(Sender: TObject);
begin
 SubForm1 := TSubForm1.CreateNew(Page1.ElementID,nil);
 SubForm2 := TSubForm2.CreateNew(Page2.ElementID,nil);
end;

Formhosting.zip (55.4 KB)

While this compiles OK, when run produces this strange error in the console:

Duplicate component name: "btCreateSubF1" | fMessage::Duplicate component name: "btCreateSubF1"
fHelpContext::0 FJSError::Error: Duplicate component name: "btCreateSubF1"

Why can I not create all forms in one go?

Form loading is an async process (going throught the same loading proc) and this cannot be simultaneously started.
Change your code to:

procedure TFrmMain.WebFormShow(Sender: TObject);

  procedure FormCreated(AForm: TObject);
  begin
    SubForm2 := TSubForm2.CreateNew(Page2.ElementID,nil);
  end;

begin
 SubForm1 := TSubForm1.CreateNew(Page1.ElementID, @FormCreated);
end;

from the Form OnShow event (so the form is ready and can be parent of your subform)

Thank you Bruno, that did the trick!