Pacific Blue Software Logo

TMS WEB Core Components Are Nil at Runtime - Causes and Fixes

TMS WEB Core Components Are Nil at Runtime - Causes and Fixes

The symptom is an error in the browser console such as Cannot read properties of null (reading 'GetElementHandle') or ... of undefined, the first time your code touches a label, edit or button that is plainly on the form. The component is nil.

Each cause below was reproduced with a small TMS WEB Core project built with the command-line compiler and run in a browser. For each one: what happens, how to recognise it, and the fix.

1. Using a Form Before It Has Loaded

A TMS WEB Core form that has an HTML template is loaded asynchronously: the HTML file is fetched from the server, and only then are the components created and the DFM values applied. CreateNew returns before that happens.

procedure TMainForm.WebFormCreate(Sender: TObject);
begin
  FSecond := TSecondForm.CreateNew(@SecondLoaded);
  // nil here - the form has not loaded yet
  console.log('After CreateNew: ' + BoolToStr(Assigned(FSecond.lblSecond), True));
end;

procedure TMainForm.SecondLoaded(AForm: TObject);
begin
  // assigned here
  console.log('In callback: ' + BoolToStr(Assigned(TSecondForm(AForm).lblSecond), True));
end;

Output:

After CreateNew: False
In callback: True

Fix: do anything that touches the new form's components in the callback passed to CreateNew, or in the form's own OnCreate, which runs after loading. Code on the line after CreateNew runs too early. The callback is a method of the calling form, passed with @.

2. The Form Unit Is Not Listed in the Project

If a form unit is reached only through another unit's uses clause and the search path, the Pascal compiles and links, but the form is not treated as a form:

After CreateNew: False
Failed to load resource: the server responded with a status of 404 (File not found)
In callback: False

Fix: list every form in the .dpr with its form comment, which also adds it to the .dproj:

uses
  Vcl.Forms,
  WEBLib.Forms,
  Second_Form in 'Second_Form.pas' {SecondForm: TWebForm} {*.html},
  Main_Form in 'Main_Form.pas' {MainForm: TWebForm} {*.html};

Look for a 404 on a form's .html file in the browser's network tab - it points straight at this cause. If the project is open in the IDE while the .dpr or .dproj is edited outside it, reload the project before building, or the IDE may save its own copy over the change.

3. An Exception While the Form Loads

TMS WEB Core turns the .dfm into Pascal code - a LoadDFMValues method that sets each property in turn. If one of those property setters raises an exception, loading stops there. The test form had a label, then a component whose setter raised, then a second label:

type
  // A label whose property setter raises, standing in for any setter that fails at runtime
  TFailingLabel = class(TWebLabel)
  private
    procedure SetFailOnLoad(const Value: Boolean);
  published
    property FailOnLoad: Boolean write SetFailOnLoad;
  end;

procedure TFailingLabel.SetFailOnLoad(const Value: Boolean);
begin
  if Value then
    raise Exception.Create('Setter failed while the form was loading');
end;

With FailOnLoad = True in the .dfm:

Fix: find the uncaught exception that happened while the form loaded - it is the first error in the console, before any nil errors - and correct the property value that caused it. Every nil error after it is a consequence.

Not every bad value raises. In testing, a TWebComboBox with ItemIndex = 5 and no items, and a TWebStringGrid with FixedCols larger than ColCount, both loaded without error.

4. A Property That Does Not Exist - and a Failed Build

A property in the .dfm that the component class does not have, or a value that is not valid for its type, does not fail at runtime. Because the .dfm is converted to Pascal, it is a compile error:

Test.Rights.Web_Main.pas (60, 13) Error: identifier not found "Fooable"

Two things make this easy to miss. The line number refers to the code generated from the .dfm, not to your source - in the test, line 60 of a unit that has 41 lines. And a failed build leaves the previous JavaScript in the output folder: in the test the .js file kept its old timestamp. Run the page and you are running the last build that worked. Anything you added since is not there, and code that depends on it fails in ways that look like nil components.

This often happens with properties copied from a VCL form. A VCL TLabel has properties that a TWebLabel does not, and the reverse.

Fix: check the build result before running, and remove or correct the property named in the error. A build script that deletes the old .js files before compiling turns a failed build into a page that does not load at all, which is far harder to overlook.

5. A Field With No Object in the DFM

A component field declared in the form class, with no matching object in the .dfm, compiles without a warning and is nil at runtime. It happens when a component is deleted from the form while its field is kept, or the object is renamed in the .dfm but not in the class.

OnCreate ran
lbl_Test assigned: True
lbl_Two assigned: False

The opposite - an object in the .dfm with no field of that name - is caught at compile time: identifier not found "lbl_Second".

Fix: keep field and object names in step. When a field is nil and the form otherwise loads normally, search the .dfm for its name first.

What Did Not Cause It

These were tested as well and did not leave components nil:

Checklist

  1. Read the first error in the browser console. An exception while a form loads makes every later error a consequence.
  2. Did the last build succeed? A failed build leaves the old JavaScript running.
  3. Is the form's .html loading, or getting a 404? If 404, add the form to the .dpr.
  4. Is the code running before the form has loaded - straight after CreateNew?
  5. Does every nil field have an object of the same name in the .dfm?

PBS Delphi - When Form Components Are Nil in TMS WEB Core


Back to Articles for Developers
Back to Articles on Delphi
How to Stop the Red Error Panel in TMS WEB Core
How to Handle Nil Pointers in TMS WebCore
Sharing Units Between VCL and TMS WEB Core

If you found this useful, then please consider making a donation.

paypal
QR Code for donation Please donate if helpful