Skip to content

JavaScript and CSS

In the previous paragraph, it was explained how a form uses a HTML file and that the HTML file can contain HTML elements, CSS, JavaScript as well as references to existing JavaScript libraries and CSS. While these references can always be manually added to the HTML file, the IDE also provides for automatic insertion or removal of such references. To do this, choose from the project context menu in the IDE the menu option:

“Manage JavaScript Libraries …”

This brings a dialog with several preconfigured popular JavaScript libraries that can be added:

From this dialog, simply check the JavaScript libraries you want to use for your project.

Using off the shelf HTML templates

This chapter explains step by step a typical scenario for adopting an existing 3rd party HTML template for use in your application. In this example, we will highlight step by step how such 3rd party template can be integrated into a TMS WEB Core web application. For this example, we will use a free off the shelf HTML template as available from https://www.creative-tim.com/ in particular the Paper Dashboard template https://www.creative-tim.com/product/paper-dashboard

This template offers a modern design and is responsive. The sidebar will collapse when the device screen is small. After downloading the template, unzip the distribution and in the main folder of the distribution we see template.html and a folder assets. The assets folder contains all css, images, fonts, JavaScript used in this template. Copy this assets folder under your project folder and import it into the project from the IDE with the “Import folder” function found in the project context menu:

After importing, all files under the assets folder are added to the project and will as such also be automatically deployed when running the application.

Next we look at template.html. This looks like:

It is this template we are going to use for a form in the TMS WEB Core application. As explained in the previous chapters, each form in a TMS WEB Core application has associated HTML. It is for this form HTML we are going to use the template. Note that the form’s HTML is loaded dynamically when the application loads the form. The application itself is started from the project HTML file.

To start using the template for a website for a TMS WEB Core application form, the first recommended step is to look into the template HTML for references to external JavaScript or CSS libraries. Moving these references to the main project HTML file has the advantage that all the libraries are already loaded by the browser when the form is being loaded. For this template, following library references are used:

We won’t use Google Maps or charts in the demo using the template, so these can be removed. All other references are cut from the template HTML file and pasted into the project HTML file. This way, the project HTML file becomes (in highlight the library references added):

Normally, we could copy the remaining HTML from the template.html file into the form’s unit1.html now and we will have the first TMS WEB Core web application based on this HTML template:

Next step will be to couple the TMS WEB Core web application to the template. The first items we will couple are the left sidebar items and the page title. The content of the TMS WEB Core form will be displayed in the content area of the template.

Sidebar

We locate in the HTML file the 3 sidebar items.

and add a unique element ID to these <p> HTML elements for the sidebar items. Adding IDs “menu1”, “menu2”, “menu3”, this becomes:

Now, we can add 3 TWebLabel components on the TMS WEB Core form and connect these labels to the

elements. This is done via the WebLabel.ElementID property.

Note that the TMS WEB Core plugin automatically detects all HTML elements where an ID is set and displays these in the dropdown for ElementID property. Further, we set for the 3 added labels ElementFont = efCSS and WidthStyle, HeightStyle to ssAuto. It will be the template that controls this label font and label size. We set the label captions to “Orders”, “Customers”, “Config” respectively as these will be the sidebar items.

Next, we do the same for the “Title” label in the template and connect it to over the ElementID property to another label on the form. This allows us to set per form a title controlled from the TMS WEB Core application code. We also want to control where the TMS WEB Core form will be displayed within this template. As the goal is to bind 3 forms to this template, the most efficient way will be to add a frame with these 3 sidebar labels that will be reused on each form.

In the template we find the content area under the navbar:

Also here, we introduce a unique ID to the element where we want the form to be rendered. The ID is “webform” and to make a form appear within this HTML element, all we need to do is set the property WebForm.FormContainer to this ID.

Note that the form’s ElementFont was set to efCSS to pickup the CSS that applies to the element where the form will rendered. We also set the ElementClassName to a CSS class defined by the template so the font of controls will match the font used in the template.

Let’s drop some controls on the TMS WEB Core form and see how the result looks in the browser:

becomes

Note that for the edit & datepicker controls, the ElementClassName was set to “form-control”, a bootstrap style. The button control ElementClassName was set to: “btn btn-primary btn-round” to show this green rounded shape.

Now it is time to add the code that will take care of loading a different TMS WEB Core form when a sidebar item is clicked. Therefore, add OnClick event handlers for the labels on the frame that are connected to the sidebar HTML elements. We create one wrapper function that can load the form by just passing the form class.

procedure TMenuFrame.LaunchForm(AInstanceClass: TFormClass);
var
  frm: TForm;

  procedure FormCreated(AForm: TObject);
  begin
    (AForm as TForm).Show;
  end;

begin
  if Uppercase(Application.ActiveForm.ClassName) <>
Uppercase(AInstanceClass.ClassName) then
  begin
    Application.CreateForm(AInstanceClass, 'body', frm, @FormCreated);
  end;
end;

Note that the FormCreated method is asynchronously loaded when the form HTML was loaded. In a browser, loading such external form HTML file is always an asynchronous process.

This way, the click handlers for the sidebar labels become simply:

procedure TMenuFrame.WebLabel1Click(Sender: TObject);
begin
  LaunchForm(TForm1);
end;

procedure TMenuFrame.WebLabel2Click(Sender: TObject);
begin
  LaunchForm(TForm2);
end;
procedure TMenuFrame.WebLabel3Click(Sender: TObject);
begin
 LaunchForm(TForm3);
end;

The end result becomes:

There is one more detail here handled in this example at template level. As we added multiple forms to the project, the template for each form in this project will be the same for one detail and that is the class for the selected item in the sidebar. Note there is a triangle indicating the selected item and the selected item is shown in orange.

So, to move the selected sidebar item to another item when a different form is loaded, the class=”active” attribute will be moved to the respective item for each of the form’s HTML templates:

Or alternatively, we could also do this in code. The advantage of doing this in code is that we could this way keep the HTML template for the 3 forms in the applications identical. This means that whenever a designer wants to modify the page, by changing one template file, all forms in the application will be updated.

For this approach, all we need to do is add element IDs to the sidebar navigation elements and then programmatically set the CSS class for the active element.

With this approach all we need to do in each form’s code is:

procedure TForm1.WebFormShow(Sender: TObject);
var
  el: TJSElement;
begin
  // set sidebar element active style
  el := document.getElementById('side1');
  el['class'] := 'active';
end;

procedure TForm2.WebFormShow(Sender: TObject);
var
  el: TJSElement;
begin
  // set sidebar element active style
  el := document.getElementById('side2');
  el['class'] := 'active';
end;

As you can see in the template file, it has a few other central items. In the top right corner, there is a search bar and a dropdown menu.

This search function and dropdown menu will return for all forms displayed in the content area of the template. So, ideally, this is handled in a centralized way. In TMS WEB Core, we can do this by means of a frame and a TWebElementActionList. As the frame is reused on all 3 forms in the application, the event handlers for the elements of the dropdown menu and the search button can be handled and centralized by the TWebElementActionList on the frame. So, first of all, set unique ID values for the dropdown menu item HTML elements and the search button HTML element. Here we will use “action1”, “action2”, “action3” and “search”.

The dropdown menu is easily recognized in the HTML template and the IDs set:

The search button is a material icon found here:

Now, we add a TWebElementActionList on the frame and add 4 actions to handle each of the clicks on the elements given an ID.

Here is the list with 4 items and the ID of the HTML element to handle the click is set to “action1”.

Finally, the OnExecute event handler code is written for the TElementActionList that will handle the events of each of the 4 actions added:

procedure TMenuFrame.WebElementActionList1Execute(Sender: TObject;
  AAction: TElementAction; Element: TJSHTMLElementRecord;
  Event: TJSEventParameter);
begin
  case AAction.Index of
  0: ShowMessage('action 1');
  1: ShowMessage('action 2');
  2: ShowMessage('action 1');
  3: ShowMessage('search');
  end;
end;
And this completes the HTML template based 3 form TMS WEB Core application.

Automatic synchronisation with HTML templates

It is not necessary to manually put UI controls on the designer for binding to HTML elements in the template. The form designer offers the capability to automatically insert UI controls on the form designer matching with the type of HTML elements in the HTML template.

This can be invoked from the form designer context menu item “Control Sync”.

So, all you need to do is add the HTML for your form to the form's HTML file and choose "HTML Sync" from the form's context menu. This will parse the HTML, and it will create an appropriate UI control on the form designer and bind it to the HTML element when it has an ID attribute value. When you change the template later, for example, add more HTML elements, you can do the "HTML Sync" again and the added corresponding UI controls will be added to the form designer. We have a fixed mapping for specific HTML elements to UI controls as well as steered sync by specifying the UI control’s class name as the attribute for the HTML element.

The automatic mapping of HTML elements to TMS WEB Core UI controls is based on the following relationship:

HTML Element UI control class
<LABEL> TWebLabel
<INPUT type=”TEXT”> TWebEdit
<INPUT type=”NUMBER”> TWebSpinEdit
<INPUT type=”CHECK”> TWebCheckBox
<INPUT type=”RADIO”> TWebRadioButton
<INPUT type=”COLOR”> TWebColorPicker
<INPUT type=”DATE”> TWebDateTimePicker
<INPUT type=”RANGE”> TWebTrackbar
<SELECT> TWebComboBox
<TEXTAREA> TWebMemo
<PROGRESS> TWebProgressbar
<UL> TWebListControl
<OL> TWebListControl
<BUTTON> TWebButton
<DIV> TWebHTMLDiv
<SPAN> TWebHTMLSpan

In addition to this automatic mapping, it is possible to steer the mapping of the HTML element to a specific UI control with the twc attribute.

For HTML elements that have the “twc” attribute and an ID, the following mapping happens upon import:

<ELEMENT twc=”classname” id=”xx”> → create a new control from class of type classname

So, the twc attribute has priority to determine the classname of the generated control.

Example:

<DIV ID=”mygrid” twc=”TWebPanel”> will cause a TWebPanel class to be bound to this HTML
DIV element on the form designer. Note that the twc attribute can also be used to exclude a HTML element with the ID set to be bound to a UI control when the twc attribute is set to “none”.

Live preview

Note that the form designer in the Delphi IDE (and also the Lazarus IDE) is based on the VCL (LCL) framework. This means that at design-time, the controls on the form designer are rendered as VCL/LCL controls. While the designer is fast, familiar, and flexible, it is still a different way of rendering it than a real web browser-based rendering. Live preview is a function that allows you to view directly in a separate browser window a live rendering of the form open in the Delphi form designer.

To start a live preview for a specific form in the project, click the form’s unit in the Delphi IDE project manager and select “Live Preview”.

This will bring up a browser (the browser is the default brower or a specific selected browser from the TMS WEB Core toolbar in the IDE).

Once the live preview is ready and shows the selected form rendered in the browser:

  • Make a change to a control's property,

or

  • Add a new control on the form or change something in the layout and

  • Press Ctrl-S.

This triggers the live preview browser window to automatically update. The trick here is that live, a single form project consisting of this form in the designer is compiled live and shown in the web browser. Evidently, also when you use HTML templates, the live preview takes this into account and gives you a real preview of this form.

Note that you can simultaneously launch multiple live previews for multiple forms. Each browser tab will then display a preview of the form selected for live preview.

Working with databases

The TMS WEB Core framework in combination with the pas2js compiler generate web client applications that run in the browser. This means that the entire application is started from a JavaScript file and runs as such in the browser. This means that any code executed in the client eventually runs as JavaScript code in the browser. Technically, after the web server sent the JS, HTML, CSS and possibly some image resources to the browser, there is no more connection to the web server. From that moment, the web client application can start to run stand-alone in the browser. All further communication with the server is typically done via HTTP REST calls (websocket communication could be a possible alternative). For designing applications using databases, this has a number of implications:

1) Classic VCL database components can NOT be used, such as FireDAC, dbExpress, ADO, or other 3rd party database access components. These are VCL components that will natively directly access the database layer on a Windows machine and the security layer of the browser would prevent such direct access anyway.

2) The database the web client application uses is typically not installed on the client machine. The browser shields database applications running on the client or in the network of the client machine for security reasons.

3) Even if a database supports a socket-based communication to perform database operations, this is typically NOT done from a web client application for security reasons. As this code is running in the browser, any experienced hacker could follow this code and could find out how to access your database and possibly invoke code himself to do malicious operations on the database.

Instead, working with databases is in this architecture of SPA’s (single-page web applications) also used with Angular, Vue, React, … done via a REST API. The web client application will authenticate & authorize against this REST API and when obtaining access, it will perform HTTP requests to perform CRUD operations on the database. It is as such the REST API server that handles the communication between client and database server and it is the REST API server that performs the database operations. The REST API server code runs on the server, can be a native application and this code cannot be seen nor affected by anyone with malicious intentions. It is very similar to a native smartphone application that connects to a central database. Also here, a typical solution is that the central database is managed by a REST API server.

TMS WEB Core is designed to be fully open with respect to the REST server providing the access to the database. As a basis, the TWebHttpRequest component can be used to perform HTTP GET/PUT/POST/DELETE requests to the REST server. Typically the REST service will expect JSON formatted data as input/output. The TJSONObject class in unit WebLib.JSON offers similar classes as offered in the System.JSON unit included standard with Delphi for VCL or FMX applications.

In addition, TMS WEB Core includes database binding mechanisms on a higher level, i.e. the level of a client dataset that will under the hood perform all necessary HTTP based communication with your REST DB server. And it includes also components for making cloud based databases accessible as datasets from your TMS WEB Core web client application.

Solutions with REST APIs for classic databases

Property Description
TXDataWebDataSet Dataset component designed for use with TMS XData REST server. This offers a code-less interface to an XData REST server with the additional advantage that XData supports meta data information. So, without additional configuration, the web client dataset TXDataWebDataSet will pickup all DB field meta data information automatically. See: https://www.tmssoftware.com/site/xdata.asp
TWebRadServerClientDataset Dataset component designed for a REST server created with Embarcadero RAD server. Create your REST API with Embarcadero RAD server to expose CRUD operations on a dataset and TWebRadServerClientDataset will handle all HTTP communication and offer client-side a dataset to connect DB-aware UI controls to See: https://www.embarcadero.com/products/rad-server
TWebSQLRestClientDataset Dataset component designed to work together with the open-source SQLDBRestBridge server. This offers a nocode configurable DB Rest Bridge server that TWebSQLRestClientDataset communicates with and offers access to via this TDataset interface. See: https://wiki.freepascal.org/SQLDBRestBridge
TWebDreamFactoryClientDataset DreamFactory offers the creation of REST APIs, including to access databases via configuration via a web interface. So, without writing code, it is possible to create your REST API for CRUD operations on a database. When such REST API is configured in DreamFactory, the TWebDreamFactoryClientDataset can automatically communicate with it and offer database access this way via its TDataset interface to DB-aware UI controls in the TMS WEB Core web client application See: https://www.dreamfactory.com

Solutions with REST APIs for cloud database solutions

Property Description
TWebMyCloudDbCLientDataset The myCloudData service offers an online cloud hosted dataset. So, here you do not need to host the database yourself, you can used an account on an already hosted database. The TWebMyCloudDbCLientDataset exposes the tables on the myCloudData service as easy to use datasets. See: https://myclouddata.net
TWebFirestoreClientDataset Google web services also includes cloud data storage with Firestore. Thanks to the TWebFirestoreClientDataset, using the Google cloud data storage becomes as seamless as possible. See https://firebase.google.com/products/firestore
TWebFaunaDbClientDataset FaunaDB is a cloud data service company that focuses on cloud enabled data storage with data stored on the server infrastructure of FaunaDB. It offers a console for configuring the tables, queries and REST API access to it. With the TWebFaunaDbClientDataset component, using data hosted at FaunaDB becomes as simple as connecting DB-aware UI controls to the dataset and you are up & running.

Existing REST APIs

In many cases, there is already a REST API available to access data or services in a company that could have been created with node.js, ASP.NET core, PHP, … When this REST API uses OAuth2 for authentication & authorization, the component TWebRESTClient can be used for OAuth2 and performing REST HTTP requests to the server. When there is no OAUTH2 based authentication & authorization, the TWebHttpRequest component can be used for all REST HTTP GET/PUT/POST/DELETE commands.