Trying to create multiple subforms does not work ...

Hi,

I've a really strange problem.

I'm trying to include two WebForms in a HTML Template.
If I add only the first it works fine.
If I add only the second if works fine, too.

But when I try to add the first and then, in the next source code line my second WebForm,
then the program flow (watched in my debugger) is really strange.

Here is the code:

unit App.MainPage;

interface

uses
  System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
  WEBLib.Forms, WEBLib.Dialogs, WEBLib.ExtCtrls, WEBLib.WebCtrls,
  WEBLib.StdCtrls, Vcl.Controls, Vcl.StdCtrls,

  Page.MenuSetup.RESTServer,
  Page.MenuSetup.UserInfo;

type
  TMainPage = class(TWebForm)
    procedure MainPageCreate(Sender: TObject);

  private
    { Private-Deklarationen }
    FPageMenuSetupRESTServer: TPageMenuSetupRESTServer;
    FPageMenuSetupUserInfo:   TPageMenuSetupUserInfo;

    procedure CreateSubForm1;
    procedure CreateSubForm2;

  public
    { Public-Deklarationen }
  end;

var
  MainPage: TMainPage;

implementation

{$R *.dfm}


procedure TMainPage.CreateSubForm1;

  procedure AfterCreate1(AForm: TObject);
  begin
    if not Assigned(AForm) then exit;

    // Handler für PageMenuSetupRESTServer -------------------------------------
    if AForm is TPageMenuSetupRESTServer then
      FPageMenuSetupRESTServer.Initialize;
  end;

begin
  FPageMenuSetupRESTServer :=
  TPageMenuSetupRESTServer.CreateNew('id_page_menu_setup_restserver_content',
                                      @AfterCreate1);
end;


procedure TMainPage.CreateSubForm2;

  procedure AfterCreate2(AForm: TObject);
  begin
    if not Assigned(AForm) then exit;

    // Handler für PageMenuSetupUserInfo ---------------------------------------
    if AForm is TPageMenuSetupUserInfo then
      FPageMenuSetupUserInfo.Initialize;
  end;

begin
  FPageMenuSetupUserInfo :=
  TPageMenuSetupUserInfo.CreateNew('id_page_menu_setup_userinfo_content',
                                    @AfterCreate2);
end;


procedure TMainPage.MainPageCreate(Sender: TObject);
begin
  CreateSubForm1;
  CreateSubForm2;
end;

end.

When I run this code the code flow is the following (see picture for line-numbers)

It starts in line 75 (CreateSubForm1),
then line 49 ( TPageMenuSetupRESTServer.CreateNew),

now I thought it should be continued with line 41 (AfterCreate1), but no,
it continues with line 76 (CreateSubForm2),
then line 67 (TPageMenuSetupUserInfo.CreateNew),
then line 59,62,63 (AfterCreate2)

Why AfterCreate1 is not called?

Is there a way to achieve the needed sequence?

I have tried to us async/await but I can't find an implementation to create embedded forms that way.

Any help is really appreciated.

Thanks for your support
Gerhard

Maybe this can help? Here's a link to a thread where a main form is used to control the visibility and placement of multiple subforms. If nothing else, it has some code snippets and some explanations about creating forms dynamically, where/when async might be applicable and so on.

Form.CreateNew() is internally asynchronous and there is at this moment not a promise based method overload for this (although this would be interesting to add). As such, launching CreateNew() twice, will cause interferences.
So, create the 2nd form in the 1st form's AfterCreate or do a form create & use the async form.Load separately with await.
I transformed the formhosting demo to show the concept.
TMSWeb_FormHosting.zip (55.1 KB)

Thanks for your tipps!

@brunofierens
I have modified your suggestion and use only one AfterCreate callback to avoid nesting multiple AfterCreate callbacks.

var
  MainPage: TMainPage;

implementation

{$R *.dfm}


procedure TMainPage.CreateSubForms;

  procedure AfterCreate(AForm: TObject);
  begin
    if not Assigned(AForm) then exit;

    // Handler für PageMenuSetupRESTServer -------------------------------------
    if AForm is TPageMenuSetupRESTServer then
    begin
      (AForm as TPageMenuSetupRESTServer).Initialize;

      // Create next Form
      FPageMenuSetupUserInfo :=
      TPageMenuSetupUserInfo.CreateNew('id_page_menu_setup_userinfo_content',
                                        @AfterCreate);
    end;

    // Handler für PageMenuSetupUserInfo ---------------------------------------
    if AForm is TPageMenuSetupUserInfo then
    begin
      (AForm as TPageMenuSetupUserInfo).Initialize;

      // Create next Form
      // FPageMenuSetupXXX :=
      // TPageMenuSetupXXX.CreateNew('id_page_menu_setup_XXX_content',
      //                                  @AfterCreate);
    end;
  end;

begin
  FPageMenuSetupRESTServer :=
  TPageMenuSetupRESTServer.CreateNew('id_page_menu_setup_restserver_content',
                                      @AfterCreate);
end;

It seems to work fine - do you think this can result in any side-effects?

Nevertheless it would be really helpfull if you could extend WebCore with a async version of CreateNew for creating forms in WebTemplate Elements.

@AndrewSimard
Wow, this is really cool stuff!!!
I will use some parts of it in my project in other units, thanks for sharing :slight_smile:

Looks good this way and indeed, a promise based CreateNew will be helpful. We've added this on our todolist for consideration.

1 Like

Thanks :slight_smile: