Took quite a bit of fiddling but I've put together a demo project for you (or anyone else) to show forms that are created at runtime (once) and then swapped in and out of a main div.
In the demo, all the forms are visible (and functioning) at the same time. So when you click on the button at the bottom, it is actually the button on the form itself - just displayed in a smaller div that acts as a placeholder. Clicking on each of the buttons basically just swaps the forms between their original placeholders and the main form viewing div. Naturally in a real project the placeholders don't need to be visible and the display div can take up the whole screen.
The code for the buttons is pretty much the same on each form, so it could be turned into a common function easily enough I'm sure. And there are likely a thousand ways to do this kind of thing, or even do it the same way with prettier code. But it works well enough I think.
Hopefully it gives you some ideas as to how this kind of approach can work in your project:
FormTest.zip (224.7 KB)
And a video in case anyone wants to see what it looks like without the hassle of running the project:
The main form code looks like this.
unit UnitMain;
interface
uses
System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs, Vcl.Controls, Vcl.StdCtrls,
WEBLib.StdCtrls, WEBLib.ExtCtrls, WEBLib.WebCtrls;
type
TFormMain = class(TWebForm)
WebPanelMain: TWebPanel;
WebMemo1: TWebMemo;
WebPanelTop: TWebPanel;
WebLabelMain: TWebLabel;
WebButtonMain: TWebButton;
WebPanelCollection: TWebPanel;
WebGridPanel1: TWebGridPanel;
WebPanelHolder: TWebPanel;
Panel1: TWebPanel;
WebHTMLDiv1: TWebHTMLDiv;
Panel2: TWebPanel;
WebHTMLDiv2: TWebHTMLDiv;
Panel3: TWebPanel;
WebHTMLDiv3: TWebHTMLDiv;
Panel4: TWebPanel;
WebHTMLDiv4: TWebHTMLDiv;
procedure WebFormCreate(Sender: TObject);
[async] procedure WebButtonMainClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Form1 :TWebForm;
Form2 :TWebForm;
Form3 :TWebForm;
Form4 :TWebForm;
CurrentForm: TWebForm;
CurrentFormElement: String;
CurrentFormSource: String;
end;
var
FormMain: TFormMain;
implementation
uses
Unit1, Unit2, Unit3, Unit4;
{$R *.dfm}
procedure TFormMain.WebButtonMainClick(Sender: TObject);
procedure AfterCreate(AForm: TObject);
begin
WebMemo1.Lines.Add((AForm as TWebForm).Caption+' Created');
if (AForm as TWebForm).Caption = 'Form1' then
begin
WebMemo1.Lines.Add('Showing Form1');
CurrentForm := Form1;
CurrentFormElement := 'WebHTMLDiv1';
CurrentFormSource := 'FormHolder1';
asm
var form = document.getElementById("WebHTMLDiv1");
document.getElementById("FormHolderMain").append(form);
setTimeout(() => { window.dispatchEvent(new Event('resize')); }, 0);
end;
end;
end;
begin
if not(Assigned(Form1)) then
begin
WebMemo1.Lines.Add('Creating Form1');
Application.CreateForm(TForm1, WebHTMLDiv1.ElementID, Form1, @AfterCreate);
end;
if not(Assigned(Form2)) then
begin
WebMemo1.Lines.Add('Creating Form2');
Application.CreateForm(TForm2, WebHTMLDiv2.ElementID, Form2, @AfterCreate);
end;
if not(Assigned(Form3)) then
begin
WebMemo1.Lines.Add('Creating Form3');
Application.CreateForm(TForm3, WebHTMLDiv3.ElementID, Form3, @AfterCreate);
end;
if not(Assigned(Form4)) then
begin
WebMemo1.Lines.Add('Creating Form4');
Application.CreateForm(TForm4, WebHTMLDiv4.ElementID, Form4, @AfterCreate);
end;
end;
procedure TFormMain.WebFormCreate(Sender: TObject);
begin
WebButtonMainClick(Sender);
end;
end.
And the forms (they're all the same basically) look like this.
unit Unit1;
interface
uses
System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs, Vcl.StdCtrls, WEBLib.StdCtrls,
Vcl.Controls, WEBLib.ExtCtrls;
type
TForm1 = class(TWebForm)
WebPanel1: TWebPanel;
WebButton10: TWebButton;
WebMemo10: TWebMemo;
procedure WebButton10Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
UnitMain;
{$R *.dfm}
procedure TForm1.WebButton10Click(Sender: TObject);
var
Element: String;
Source: String;
begin
if Assigned(FormMain.CurrentForm) then
begin
if (FormMain.CurrentForm <> FormMain.Form1) then
begin
FormMain.WebMemo1.Lines.Add('Hiding '+(FormMain.CurrentForm as TWebForm).Caption);
// Local variables to use in JS
Element := FormMain.CurrentFormElement;
Source := FormMain.CurrentFormSource;
// Assignments for new form
FormMain.CurrentForm := FormMain.Form1;
FormMain.CurrentFormElement := 'WebHTMLDiv1';
FormMain.CurrentFormSource := 'FormHolder1';
// Hide currently shown form
asm
var oldform = document.getElementById(Element);
document.getElementById(Source).append(oldform);
var newform = document.getElementById('WebHTMLDiv1');
document.getElementById('FormHolderMain').append(newform);
setTimeout(() => { window.dispatchEvent(new Event('resize')); }, 0);
end;
FormMain.WebMemo1.Lines.Add('Showing '+(FormMain.CurrentForm as TWebForm).Caption);
end;
end;
end;
end.
The main project source looks like this (updated from the zip file, but functionally the same).
program Project1;
uses
Vcl.Forms,
WEBLib.Forms,
UnitMain in 'UnitMain.pas' {FormMain: TWebForm} {*.html},
Unit1 in 'Unit1.pas' {Form1: TWebForm} {*.html},
Unit2 in 'Unit2.pas' {Form2: TWebForm} {*.html},
Unit3 in 'Unit3.pas' {Form3: TWebForm} {*.html},
Unit4 in 'Unit4.pas' {Form4: TWebForm} {*.html};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TFormMain, FormMain);
// Application.CreateForm(TForm1, Form1);
// Application.CreateForm(TForm2, Form2);
// Application.CreateForm(TForm3, Form3);
// Application.CreateForm(TForm4, Form4);
Application.Run;
end.
So none of the subforms are created until needed, but they only need to be created once.