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;
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;
…
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;
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:
So, the twc attribute has priority to determine the classname of the generated control.
Example:
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.