Introduction
You need to use HTMX for ordinary web coding which you were used to solving using JavaScript and HTML without using the simplicity that HTMX offers.
There are multiple advantages to doing this. As part of that we are exploring how to get a progress bar display.
What is a progress bar indicator?
A progress bar is a graphical control element used to visualize the progression of an extended computer operation, such as a download, file transfer, or installation. Sometimes, the graphic is accompanied by a textual representation of the progress in a percent format. The concept can also be regarded to include "playback bars" in media players that keep track of the current location in the duration of a media file.
I got above definition from wikipedia. I think of progress bar as being really effective in knowing how far a code has achieved its purpose. It could be installation or uninstall, it could be security scan. Usually progress bar involves some sort of progress update with text as well as graphical display or a horizontal bar with some thickness.
Various other displays exist too.
What is HTMX?
HTMX is a replacement for HTML and JSON based work which we are used to. Carson Gross came up with this JavaScript plugin to replace JavaScript and JSON with old school HTML tags and events.
For this purpose however we are specifically employing the hx-trigger HTMX attribute along with hx-target, hx-swap.
This is standard HTMX in whch you use a bunch of HTMX attributes to update page without a reload.
This is new way of using less load on server.
Code sample and demo
In our code sample we do have a bunch of fake server code to mimic a HTMX POST but this should work with any standard server which you use like express or nginx, apache or whatever.
This is progbar.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> Progress Bar</title>
<link rel="canonical"
href="https://htmx.org/examples/progress-bar/">
<link rel="alternate" type="application/atom+xml" title="Sitewide
Atom feed" href="/atom.xml">
<link rel="stylesheet" href="/css/site.css">
<script src="/js/htmx.js"></script>
<script src="/js/class-tools.js"></script>
<script src="/js/preload.js"></script>
<script src="/js/_hyperscript.js"></script>
<meta name="generator" content="Zola v.TODO">
</head>
<body hx-ext="class-tools, preload">
<div class="c content ">
<h1>Progress Bar</h1>
<script src="https://unpkg.com/sinon@9.0.2/pkg/sinon.js"></script>
<script src="/js/demo.js"></script>
<p>This progress bar is updated every 600 milliseconds, with the “width”
style attribute and <code>aria-valuenow</code> attributed set to current
progress value.
Because there is an id on the progress bar div, htmx will smoothly
transition between requests by settling the
style attribute into its new value. This, when coupled with CSS
transitions, makes the visual transition continuous
rather than jumpy.</p>
<p>Finally, when the process is complete, a server returns
<code>HX-Trigger: done</code> header, which triggers an update of the UI
to “Complete” state
with a restart button added to the UI (we are using the <a
href="https://htmx.org/extensions/class-tools/"><code>class-tools</code></a>
extension in this example to add fade-in effect on the button):</p>
<style>
#demo-server-info {
padding: 8px;
position: fixed;
bottom: 0;
right: 0;
left: 0;
height: 64px;
width: 100vw;
background-color: whitesmoke;
border-top: 2px solid gray;
overflow: hide;
margin: 0px;
z-index: 1;
}
#demo-server-info.show {
max-height: 45vh;
height: 500px;
overflow: scroll;
}
#demo-activity {
height:300px
}
#demo-activity div {
vertical-align: top
}
#demo-activity ol li {
list-style-position: inside;
}
#demo-canvas {
margin-bottom: 500px;
padding-top: 12px;
}
</style>
<script>
function toggleRequestInfo() {
var classList =
document.getElementById("demo-server-info").classList;
classList.toggle("show");
if (classList.contains('show')) {
document.getElementById("request-info-toggler").innerHTML =
"↓ Hide"
} else {
document.getElementById("request-info-toggler").innerHTML =
"↑ Show"
}
}
</script>
<div id="demo-server-info">
<div>Server Requests<span id="request-count"></span> <a
id="request-info-toggler" onclick="toggleRequestInfo()" style="cursor:
pointer">↑ Show</a></div>
<div id="demo-activity" class="row">
<div class="3 col" >
<ol id="demo-timeline" reversed>
</ol>
</div>
<div id="demo-current-request" class="9 col">
</div>
</div>
</div>
<h2><a class="zola-anchor" href="#demo" aria-label="Anchor link for:
demo"></a>Demo of progress using htmx</h2>
<div id="demo-canvas">
</div>
<style>
.progress {
height: 20px;
margin-bottom: 20px;
overflow: hidden;
background-color: #f5f5f5;
border-radius: 4px;
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
}
.progress-bar {
float: left;
width: 0%;
height: 100%;
font-size: 12px;
line-height: 20px;
color: #fff;
text-align: center;
background-color: #337ab7;
-webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
-webkit-transition: width .6s ease;
-o-transition: width .6s ease;
transition: width .6s ease;
}
#restart-btn {
opacity:0;
}
#restart-btn.show {
opacity:1;
transition: opacity 100ms ease-in;
}
</style>
<script>
//=========================================================================
// Fake Server Side Code
//=========================================================================
// routes
init("/demo", function(request, params){
return startButton("Start Progress");
});
onPost("/start", function(request, params){
var job = jobManager.start();
return jobStatusTemplate(job);
});
onGet("/job", function(request, params){
var job = jobManager.currentProcess();
return jobStatusTemplate(job);
});
onGet("/job/progress", function(request, params, responseHeaders){
var job = jobManager.currentProcess();
if (job.complete) {
responseHeaders["HX-Trigger"] = "done";
}
return jobProgressTemplate(job);
});
// templates
function startButton(message) {
return `<div hx-target="this" hx-swap="outerHTML">
<h3>${message}</h3>
<button class="btn" hx-post="/start">
Start Job
</button>
</div>`;
}
function jobProgressTemplate(job) {
return `<div class="progress" role="progressbar" aria-valuemin="0"
aria-valuemax="100" aria-valuenow="${job.percentComplete}"
aria-labelledby="pblabel">
<div id="pb" class="progress-bar"
style="width:${job.percentComplete}%">
</div>
</div>`
}
function jobStatusTemplate(job) {
return `<div hx-trigger="done" hx-get="/job" hx-swap="outerHTML"
hx-target="this">
<h3 role="status" id="pblabel" tabindex="-1" autofocus>${job.complete
? "Complete" : "Running"}</h3>
<div
hx-get="/job/progress"
hx-trigger="${job.complete ? 'none' : 'every 300ms'}"
hx-target="this"
hx-swap="innerHTML">
${jobProgressTemplate(job)}
</div>
${restartButton(job)}`;
}
function restartButton(job) {
if(job.complete){
return `
<button id="restart-btn" class="btn" hx-post="/start" classes="add show:300ms">
Restart Job
</button>`
} else {
return "";
}
}
var jobManager = (function(){
var currentProcess = null;
return {
start : function() {
currentProcess = {
complete : false,
percentComplete : 0
}
return currentProcess;
},
currentProcess : function() {
currentProcess.percentComplete
+= Math.min(100, Math.floor(33 * Math.random()));
currentProcess.complete =
currentProcess.percentComplete >= 100;
return currentProcess;
}
}
})();
</script>
</div>
</body>
</html>
Conclusion
The way progress bar update is simulated without any timer or needless JS , still using JS on server side in same page is interesting.
HTMX does not force you to dump JS but use it minimally and gracefully.
Answer
What is security by obscurity?
Security through obscurity (STO) is a security strategy that involves hiding a system's details or mechanisms to improve its security. The idea is that if the details aren't publicly known, then it will be more difficult for potential attackers to identify and exploit vulnerabilities. STO is often criticized as an ineffective method, especially when used as the primary or only form of security
Question
What is a time slice?
Feedback
The way you get 20,000$ as monthly income(MRR) is by coding a spectacular product and then acquiring customers by marketing online.
Organic marketing is best. It all begins with a spectacular product that you code alone. I love bootstrapped businesses that run with 0 employees.