B4J Question [WebApp] How to create a web page dynamically?

In b4j with jServer I would like to make a web page dynamically, without using the index.html file. I'll try to explain it in another way, in case I don't make myself understood. What I want is to create the page from scratch, using the attributes from <html> to </html> and send it to display. Something like in PHP where one has the logic and based on what one wants, the html content is created that commands it to be displayed as the output of the executed program. Is this possible?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Is this possible?
Of course.

Very simple example:
B4X:
srvr.AddHandler("/index.html", "IndexGenerator", False)

B4X:
'Handler class
Sub Class_Globals
    
End Sub

Public Sub Initialize
    
End Sub

Sub Handle(req As ServletRequest, resp As ServletResponse)
    resp.Write($"
    <html>
    <body>
    <p>
    The time now is ${DateTime.Time(DateTime.Now)}
    </p>
    </body>
    </html>
    "$)
End Sub
 
Upvote 0
Your example work fine, but see this escenario:
I put the html content of the guessmynumber example in the handle resp.Write and it did show the page, but I cann't read the fields of this form because when I did press the guess button not action is triggered, seems than that is not readed. This is my code:


Sub AppStart (Args() As String)
srvr.Initialize("srvr")
srvr.Port = 51042
srvr.AddHandler("/index.html", "GuessMyNumber", False)
srvr.Start
StartMessageLoop
'open browser and navigate to: http://127.0.0.1:51042/index.html
End Sub
-------------------
class module / Server Handler / GuessMyNumber
-------------------
Sub Handle(req As ServletRequest, resp As ServletResponse)
Try
If req.GetSession.HasAttribute("myNumber") = False Then
req.GetSession.SetAttribute("myNumber", Rnd(0, 101))
End If
Dim myNumber As Int = req.GetSession.GetAttribute("myNumber")
Dim n As String = req.GetParameter("number")
If IsNumber(n) = False Then
resp.Write("Please enter a valid number.")
Else
If n > myNumber Then
resp.Write("My number is smaller.")
Else If n < myNumber Then
resp.Write("My number is larger.")
Else
resp.Write("Well done!!!")
End If
End If
Catch
resp.SendError(500, "error....")
End Try
resp.Write($"
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta content="text/html; charset=UTF8" http-equiv="content-type">
<title>Guess My Number</title>
<script src="https://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<style>
html {
height: 100%;
}
body {
height: 100%;
background-repeat: no-repeat;
background-attachment: fixed;
background: #f0f9ff; /* Old browsers */
background: -moz-linear-gradient(top, #f0f9ff 0%, #cbebff 47%, #a1dbff 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f0f9ff), color-stop(47%,#cbebff), color-stop(100%,#a1dbff)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* IE10+ */
background: linear-gradient(to bottom, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* W3C */
}
</style>
</head>
<body>
<h1>Guess My Number</h1>
Enter number: <input type="text" id="txtNumber"></input>
<button type="button" id="btnGuess">Guess!</button><br/><br/>
<button type="button" id="btnReset">Reset secret number</button><br/>
<p id="result"></p>

<script type="text/javascript">
$("#btnGuess").click(function(){
$.post("guess", "number=" + txtNumber.value,
function(data) {
$("#result").html(data);
$("#txtNumber").focus();
$("#txtNumber").select();
}

);
});
$("#txtNumber").keyup(function(event){
if(event.keyCode == 13){
$("#btnGuess").click();
}
} );
$("#btnReset").click(function(){
$.post("reset");
});
</script>

<p>
The time now is ${DateTime.Time(DateTime.Now)}
</p>
</body>
</html>
"$)

End Sub

Thank you for your help.
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
I would use 3 handlers when things get complex (but I show at the end of this post how you could do it in one too):
1. GuessMyNumberHTML: to write the html
2. GuessMyNumber: to handle the "guess" button path -> in JavaScript: $.post("guess", "number=" + txtNumber.value, ... );
3. ResetMyNumber: to handle the "reset" button path -> in JavaScript: $.post("reset");

Main:
B4X:
Sub Process_Globals
    Private srvr As Server
End Sub

Sub AppStart (Args() As String)
    srvr.Initialize("srvr")
    srvr.Port = 51042
    srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
    srvr.AddHandler("/guessmynumber/guesspage", "GuessMyNumberHTML", False) ' the dynamic html
    srvr.AddHandler("/guessmynumber/guess", "GuessMyNumber", False) ' handler for the Guess button
    srvr.AddHandler("/guessmynumber/reset", "ResetMyNumber", False) ' handler for the Reset button
    srvr.Start
    StartMessageLoop
    'open browser and navigate to: http://127.0.0.1:51042/guessmynumber/guesspage <------------------
End Sub

GuessMyNumberHTML:
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
    resp.Write($"
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta content="text/html; charset=UTF8" http-equiv="content-type">
<title>Guess My Number</title>
<script src="https://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<style>
html {
height: 100%;
}
body {
height: 100%;
background-repeat: no-repeat;
background-attachment: fixed;
background: #f0f9ff; /* Old browsers */
background: -moz-linear-gradient(top, #f0f9ff 0%, #cbebff 47%, #a1dbff 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f0f9ff), color-stop(47%,#cbebff), color-stop(100%,#a1dbff)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* IE10+ */
background: linear-gradient(to bottom, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* W3C */
}
</style>
</head>
<body>
<h1>Guess My Number</h1>
Enter number: <input type="text" id="txtNumber"></input>
<button type="button" id="btnGuess">Guess!</button><br/><br/>
<button type="button" id="btnReset">Reset secret number</button><br/>
<p id="result"></p>

<script type="text/javascript">
$("#btnGuess").click(function(){
$.post("guess", "number=" + txtNumber.value,
function(data) {
$("#result").html(data);
$("#txtNumber").focus();
$("#txtNumber").select();
}

);
});
$("#txtNumber").keyup(function(event){
if(event.keyCode == 13){
$("#btnGuess").click();
}
} );
$("#btnReset").click(function(){
$.post("reset");
});
</script>

<p>
The time now is ${DateTime.Time(DateTime.Now)}
</p>
</body>
</html>
"$)
End Sub

GuessMyNumber (handles the JavaScript REST API call post 'guessmynumber/guess' )
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
    Try
        If req.GetSession.HasAttribute("myNumber") = False Then
            req.GetSession.SetAttribute("myNumber", Rnd(0, 101))
        End If
        Dim myNumber As Int = req.GetSession.GetAttribute("myNumber")
        Dim n As String = req.GetParameter("number")
        If IsNumber(n) = False Then
            resp.Write("Please enter a valid number.")
        Else
            If n > myNumber Then
                resp.Write("My number is smaller.")
            Else If n < myNumber Then
                resp.Write("My number is larger.")
            Else
                resp.Write("Well done!!!")
            End If
        End If
    Catch
        resp.SendError(500, "error....")
    End Try
End Sub

ResetMyNumber (handles the JavaScript REST API call post 'guessmynumber/reset')
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
    req.GetSession.RemoveAttribute("myNumber")
End Sub

Doing it in one handler. Needs a couple of changes:
1. handle sub paths of /guess (with * )
2. change the $.post paths to sub paths in the javascript

Main:
B4X:
Sub Process_Globals
    Private srvr As Server
End Sub

Sub AppStart (Args() As String)
    srvr.Initialize("srvr")
    srvr.Port = 51042
    srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")   
    ' notice the * at the end as we want to be able to also handle the sub paths /guess/check and /guess/reset
    srvr.AddHandler("/guessmynumber/guess/*", "GuessMyNumber", False)
    srvr.Start
    StartMessageLoop
    'open browser and navigate to: http://127.0.0.1:51042/guessmynumber/guess <-------------------------------
End Sub

GuessMyNumber:
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
    If req.RequestURI.EndsWith("/check") Then   
        Try
            If req.GetSession.HasAttribute("myNumber") = False Then
                req.GetSession.SetAttribute("myNumber", Rnd(0, 101))
            End If
            Dim myNumber As Int = req.GetSession.GetAttribute("myNumber")
            Dim n As String = req.GetParameter("number")
            If IsNumber(n) = False Then
                resp.Write("Please enter a valid number.")
            Else
                If n > myNumber Then
                    resp.Write("My number is smaller.")
                Else If n < myNumber Then
                    resp.Write("My number is larger.")
                Else
                    resp.Write("Well done!!!")
                End If
            End If
        Catch
            resp.SendError(500, "error....")
        End Try
        Return
    End If
    If req.RequestURI.EndsWith("/reset") Then
        req.GetSession.RemoveAttribute("myNumber")
        Return
    End If
    ' else write the html
    ' NOTE: I changed the POST paths!
    ' $.post("guess/check"...
    ' $.post("guess/reset"
    resp.Write($"
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta content="text/html; charset=UTF8" http-equiv="content-type">
<title>Guess My Number</title>
<script src="https://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<style>
html {
height: 100%;
}
body {
height: 100%;
background-repeat: no-repeat;
background-attachment: fixed;
background: #f0f9ff; /* Old browsers */
background: -moz-linear-gradient(top, #f0f9ff 0%, #cbebff 47%, #a1dbff 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f0f9ff), color-stop(47%,#cbebff), color-stop(100%,#a1dbff)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* IE10+ */
background: linear-gradient(to bottom, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%); /* W3C */
}
</style>
</head>
<body>
<h1>Guess My Number</h1>
Enter number: <input type="text" id="txtNumber"></input>
<button type="button" id="btnGuess">Guess!</button><br/><br/>
<button type="button" id="btnReset">Reset secret number</button><br/>
<p id="result"></p>

<script type="text/javascript">
$("#btnGuess").click(function(){
$.post("guess/check", "number=" + txtNumber.value,
function(data) {
$("#result").html(data);
$("#txtNumber").focus();
$("#txtNumber").select();
}

);
});
$("#txtNumber").keyup(function(event){
if(event.keyCode == 13){
$("#btnGuess").click();
}
} );
$("#btnReset").click(function(){
$.post("guess/reset");
});
</script>

<p>
The time now is ${DateTime.Time(DateTime.Now)}
</p>
</body>
</html>
"$)
End Sub

Alwaysbusy
 
Upvote 0
Top