If you ever wanted to create a server-based web application, then HTMX is a solution that offers great flexibility for development, allowing RAD Studio developers to deliver the business logic while still allowing designers to make the web application look great using CSS. Without having to write a single line of JavaScript code, you can build a full web application, with the entire logic in a web server. And what would be the best language for such a web server? Of course, it’s Delphi.
In this post, we’ll talk about the popular HTMX library and its integration with Delphi. We will also see a very basic demo of a web application running entirely on Delphi code using the WebBroker, with HTMX for the server-side requests.
Table of Contents
What is HTMX?
HTMX is a JavaScript library, but it can just as well be seen as an HTML extension, since all of its logic happens in HTML, without the need to write JavaScript. It is most often used as an alternative to JavaScript frameworks like React, Angular or Vue, but uses a fundamentally different approach, which is AJAX requests. With AJAX (or Asynchronous JavaScript and XML), web applications can send and retrieve data from a server asynchronously, without having to interfere with the web page itself and without having to reload it. HTMX allows us to send data from the web page to a web server and retrieve HTML code as a response, which can then be replaced inside the web page.
The idea behind the strategy is for the most part to be independent of JavaScript. By using HTMX no (self-written) JavaScript code is involved, and instead all of the logic of the application happens on the server side. This has plenty of advantages, including privacy and the ability to use existing codebases, no matter which programming language. The separation of the logic from the web is also something many developers appreciate.
Why use HTMX with Delphi?
HTMX offers the opportunity to write entire web applications, with all of the logic in a web server. The web server can be written in any programming language you want, as long as it is fast and efficient. The best choice for such a web server is Delphi, since it is highly-capable, object-oriented and one of the fastest languages on the market.
The most potential of this technology for Delphi developers does not necessarily lie in writing new applications, but in putting old VCL codebases in a web server and using those for writing web applications. This way Delphi desktop applications can be fully migrated to the web, without needing to rewrite all of the code in JavaScript, which saves huge amounts of time and effort.
Step 1: Creating the web server
Creating the web server as a console application with the WebBroker is very straightforward. In RAD Studio select File > New > Other. In the new Items dialog box, select the Web tab under Delphi and select Web Server Application. Windows will be the default platform and you can additionally select Linux. Go next and select console application, then finish. Save the project in a path of your choice and your web server is ready to go. Compile and start the server, then a terminal window will open. Enter “start” and the server will be accessible under the port that you entered (default is 8080). Open localhost:8080 in a browser and you should see your app.
Step 2: Preparing the HTML and HTMX
The outer canvas of a web page is shaped in HTML. So let’s create a simple HTML page. Create a file index.html and paste the following.
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Delphi & HTMX Demo</title> </head> <body> </body> </html> |
Notice the <script src=”…”></script> line. This is the only thing we need to include HTMX in our project. No need to download anything, just add this line and HTMX is ready to go.
In order to display the index.html the web server needs to return the contents of the file. The default handler is located in the unit WebModuleUnit1.pas, where there is already a plain HTML template returned. Let’s replace this with our index.html file:
1 2 3 4 5 |
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin Response.Content := TFile.ReadAllText('index.html'); //full path to the file end; |
Here you either have to use the absolute path to the file or copy the file to the destination dir. Recompile and restart the server and you should see our empty HTML page.
Step 3: Hello World
Let’s fill our page with a little bit of life with a simple “Hello World” example. The goal is to have a label and a button, and by clicking the button the caption of the label will be “Hello World”. So, first add a label and a button to the <body>.
1 2 |
<h1 id="header">Delphi & HTMX Rocks!</h1> <button hx-get="/helloworld" hx-target="#header">Click me</button> |
Notice the hx- attributes. This is our HTMX “code”. What this basically means is when the button is clicked, execute the GET-Request /helloworld and put the response into the caption of the label. So, the next step is to implement the GET-Request in the server.
For this, navigate to the object inspector in the designer and open the actions editor. There you can create a new action, select mtGET as the method type, give it a name and enter /helloworld for the PathInfo. Navigate to events and create a new event for it. You should have an event like this:
1 2 3 |
procedure TWebModule1.WebModule1HelloWorldAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin end; |
Now we are just going to return “Hello World” as a response.
1 |
Response.Content := 'Hello World!'; |
Your first Hello World app is finished! See how straight-forward web development can be? Let’s take this a bit further.
Step 4: A step further
The goal now is to have an edit and a button. The edit is read-only, but when the user clicks the “Edit” button the edit becomes editable and the “Edit” button changes to a “Submit” button. After clicking “Submit”, the entered text in the edit will be the caption of another label. First, the HTML:
1 2 3 4 |
<form hx-get="/edit" hx-swap="outerHTML"> <input type="text" name="edit" readonly/> <button>Edit</button> </form> |
What we have here is a form with an (read-only) edit and an “Edit” button. When the button is clicked, a GET-Request along with the value of the edit will be executed. The result will be HTML, which is going to replace the entire form. In HTMX, this is called a “swap”. Let’s implement the /edit request. First, create an action, just like we did in Step 3. In the request we want to read the value of the edit and replace the entire form with HTML. The HTML will simply be a string constant, for which we can use one of the best features of Delphi 12, the multi-line string literals.
1 2 3 4 5 6 7 8 9 10 11 |
procedure TWebModule1.WebModule1EditAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); const cEdit = ''' <form hx-post="/submit" hx-swap="outerHTML"> <input type="text" name="edit" value="%s"/> <button>Submit</button> </form> '''; begin end; |
The HTML there is nearly the same as before, but the edit is not readonly and the “Edit” button is now a “Submit” button. Additionally we now have a POST-Request called “/submit” and we format the text from before in the new edit. Of course, at the beginning this will be empty.
1 2 3 4 5 6 |
var lResponse: string; begin lResponse := Request.ContentFields.Values['edit']; Response.Content := string.Format(cEdit, [lResponse]); end; |
lResponse reads the next from before, which we included in the GET-Request and we format this into our response.
Now the POST-Request /submit. Add an action like before, now with mtPOST as MethodType. First declare a constant for the HTML to return, which will be the same that we wrote into the index.html file.
1 2 3 4 5 6 7 8 9 10 11 12 |
procedure TWebModule1.WebModule1SubmitAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); const cSubmit = ''' <form hx-get="/edit" hx-swap="outerHTML"> <input type="text" name="edit" value="%s" readonly/> <button>Edit</button> <label>%s</label> </form> '''; begin end; |
Notice the label. There we are going to format the edited result in. Now do the same as before.
1 2 3 4 5 6 |
var lResponse: string; begin lResponse := Request.ContentFields.Values['edit']; Response.Content := string.Format(cSubmit, [lResponse, lResponse]); end; |
If you want to try the demo yourself you can find it in our GitHub repo. Keep in mind that it will only work with Delphi 12.0 or above.
That was it! Recompile and restart and you will see the results. Click “Edit”, enter a text in the edit control, click “Submit” and the entered text will appear in a label.
We are working on another blog post where we will make this same demo look more modern and up-to-date with just a few changes using the library PicoCSS. Here’s a sneak peek of how it will look. Stay tuned!
Article written by Elias Kassebaum.
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition
I understand the Privacy’s advantage, but wont that design choice consume more processing power than having some logic executed by the client in order to offload server load?
Cheers.
Wikarina
Technically, yes: the server has to parse and send the HTML snippet back, but this is a very lightweight process, mostly with modern hardware. Usually, the bottlenecks are on databases and other services.
Of course, HTMX vs. frontend JS frameworks have benefits and drawbacks, and each technology fits different scenarios. However, I do believe that HTMX could be used in a high percentage of websites, simplifying enormously the complexities of having 2 fully independent projects (frontend and backend).
For me, personally, the main benefit of using HTMX is bringing back the state of a webapp only to one place: the backend, having only one source of truth but keeping a SPA-like experience for the final user. Handling 2 states can get very, very complex, and that leads to inconsistencies and constant checks and validations.
We are planning on writing more blog posts about this technology, so stay tuned 😉
I have a windows computer but use a Linux server. What files need to be on the server?
Hi Jim,
All the required files for these HTMX demos are already included in the binary generated! That’s one of the demos’ strongest points: your HTML snippets are embedded in your binary, so no extra files are needed.
That said, to compile a Linux application using Delphi, you will need to use PAServer, but that’s the common way of doing it — same process as any other project.
D2Bridge Framework is Delphi Web, just it!
Thanks for your msg Paulo!
D2Bridge is indeed a cool project! The main issue I find for myself is how tightly coupled it is with Bootstrap. I personally prefer a more UI-agnostic approach, so I can pick and choose whichever UI suits my needs based on the project requirements. However, to create a website quickly, and as long as the pre-configured Bootstrap components suit your needs, it’s definitely a great option. 🙂
This does not work. The HelloWorld is never triggered. I have copied the code from GIT, and stepped through it. All that happens is the edit box is duplicated.
Hmm, Ill pass this comment on to Antonio so he’s got a chance to look at it and get back to you. It worked when I tested it recently.
Hi Chris, I just downloaded the example and tested it in RAD Studio 12.2 and it seemed to work fine for me.