Form handling errors in 2.7

Has there been a change in how forms are handled? When I try and close a form, I get errors like these:

Uncaught TypeError: Cannot use 'in' operator to search for '4' in undefined
    at Object.GetElementBindHandle (WEBLib.Forms.pas:2264:19)
    at Object.UnbindEvents (WEBLib.Controls.pas:5170:15)
    at Object.UnbindEvents (WEBLib.Forms.pas:1978:3)
    at Object.Close (WEBLib.Forms.pas:1207:5)
    at Object.btnClosePopupClick (UnitPopup.pas:33:3)
    at Object.cb (rtl.js:254:1)
    at Object.Click (WEBLib.Controls.pas:1854:5)
    at Object.Click (WEBLib.StdCtrls.pas:3673:3)
    at Object.HandleDoClick (WEBLib.Controls.pas:3925:5)
    at HTMLButtonElement.cb (rtl.js:250:1)Understand this errorAI
classes.pas:5644 Uncaught (in promise) TypeError: Cannot use 'in' operator to search for '3' in undefined
    at Object.BeforeDestruction (classes.pas:5644:23)
    at c.$destroy (rtl.js:368:1)
    at Object.freeLoc (rtl.js:470:1)
    at Object.WebButton1Click (Unit1.pas:56:13)

I've attached a minimal project where you can see these being generated.
FormDemo.zip (1.7 MB)

In Form1, I have a button to create a popup form like this:

procedure TForm1.WebButton1Click(Sender: TObject);
var
  newform: TFormPopup;
begin
  newform := TFormPopup.Create(Self);
  newform.Popup := True;

  // load file HTML template + controls await(TForm2, newform.Load());
  // init control after loading newform.frm2Edit.Text := WebEdit1.Text;

  await( TFormPopup, newform.Load );

  try
    // excute form and wait for close
    await(TModalResult, newform.Execute);
  finally
    newform.Free;
  end;

end;

And in FormPopup, I'm just trying to close the form.

procedure TFormPopup.btnClosePopupClick(Sender: TObject);
begin
  ModalResult := mrOk;
  Close;
end;

procedure TFormPopup.WebFormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

Not sure where I've gone wrong.

I use the same mechanism without issue on 2.7.0.1. I think you issue is you are setting the Action to caFree ( which caused the form to free itself) and then you are freeing the form again where it is being called. Remove the caFree and that will fix. You are freeing the form twice.

1 Like

Well that's odd.

In my test project, I had added that thinking it was what was missing. I removed the Action := caFree as well as the ModalResult := mrOk (because I don't care about that) and it works great.

But in my larger project where I have this problem, I don't recall having these set either, but I had added them, again thinking it was the culprit. But when I removed them, the larger project works ok now too. Bizarre.

All seems good now though. Not sure what to say.

Thanks!

Update... Hmm... I didn't get any errors, but then I realized I had commented out the equivalent of newForm.free (in my larger project) which meant that the form was removed from the DOM but still declared. When I added it back in, one of those errors popped up again. I added a short delay before the free and now there appear to be no issues. So I think something changed in 2.7 in this regard but it can be mitigated by paying close attention to the timing?

We actually improved the code somewhat to have the behavior match the VCL behavior closer.

The consequence of that that affects your code

  1. You set ModalResult = mrOK which internally causes a Close , making your Close call no longer needed.

  2. You use CloseAction = caFree, which causes the form to internally destroy itself. But in your finally clause, you destroy this already destroyed form again.

So, these issues cause this error.

Solve this with:

procedure TFormPopup.btnClosePopupClick(Sender: TObject);
begin
  ModalResult := mrOk;
end;

and

procedure TForm1.WebButton1Click(Sender: TObject);
var
  newform: TFormPopup;
begin
  newform := TFormPopup.Create(Self);
  newform.Popup := True;

  // load file HTML template + controls await(TForm2, newform.Load());
  // init control after loading newform.frm2Edit.Text := WebEdit1.Text;

  await( TFormPopup, newform.Load );

  try
    // excute form and wait for close
    await(TModalResult, newform.Execute);
  finally
  end;
end;
1 Like

Ok, I've gotten rid of the error, all good, thank you.

Follow-up question though. If in Form1 I declare newform as a form variable rather than just in this function, after the modal closes, the form variable is not null. Setting Action := caFree in the popup form produces one of those errors.

If I call newform.free in the finally block, this also doesn't work unless I add a short delay?

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

If you set CloseAction = caFree, then the form destroys itself upon close. So, any reference to this form, regardless from where, is a reference to a form that was destroyed, i.e. no longer valid.