B4J Tutorial [BANanoVuetifyAD3] Creating Server Applications with BANanoServer...

Ola..

Update: 12 July 2021: Here is a working example with jRDC2 MySQL

DO NOT USE THE APPROACH DISCUSSED HERE.

UPDATE 07 May 2021: Please note that this is currently experimental. Ran into some hurdles for now making this work well. Please DONT USE. I will keep you posted on developments.

Join our Telegram Channel

An introduction...
untitled_page.png


In a normal BANanoVuetifyAD3 app, we have BANano, on BANano_Ready we can create our DB connections, create tables etc. We then initialize pgIndex which we use to build our app. Our app is built with one or more pages which are created via code modules which are then added as Routers i.e. pages / handlers via the AddRouter sub. After that we .Server our application.

The back-end connections can be done directly from the pgIndex module and also via the other handlers we have and usually this is directl. Whether we use MSSQL, MySQL, BANanoSQL, SQLIte (the three via PHP), special classed for connectivity are built in within the framework which make seamless transition in terms of following the same methodology.

On the other hand, BANanoServer i.e. jServer, works a differently.

The recommended way to create BANanoVuetifyAD3 BANanoServer Apps, is the following:

1. We have a BROWSERIndex module - this will act the same way as our pgIndex module however any database connections will be done via another code module.
2. We have a SERVERIndex module - this will contain all B4J source code that we want to run on the server. All relevant B4J + Other libraries code is acceptable here.
3. We have a SHARED??? module - this will contain both BANano + B4J code that we want to run wether on the BANano Front-end / BANanoServer backend.

For the BANanoServer, the BROWSER?, SERVER? and SHARED? modules are mandatory for our implementation. You can read more from the BANanoServer documentation about this.

BROWSER and SERVER are B4J "handlers". For BANanoVuetifyAD3, adding "handlers" i.e. routers, we will follow the same methodology we have been using. This is.

1. The code we wrote on pgIndex, we now write on BROWSERIndex.
2. We create routers i.e. handlers the same way we did before. We did this by creating a code module and then initialized this on the AddRouters sub in pgIndex. This sub will now be in BROWERIndex.
3. Like before we .Server our app to run it.
4. For our DB connections, we are not using PHP like before, but are using the SQL library, just like one would normally with an ABM application or any B4J app as conversations with the back-end are now directly via jServer.

So what happens when one clicks a CRUD related button on the browser?

PS: Please note the location of the BANanoServer library, copy it to your external libraries folder.

1612087174114.png
 

Attachments

  • 1612087158363.png
    1612087158363.png
    12.7 KB · Views: 255
Last edited:

Mashiane

Expert
Licensed User
Longtime User
So what happens when one clicks a CRUD related button on the browser?

The button path will be followed with the blue 1. ToServer lines above.

CREATING A RECORD

1. One clicks a button, the query to be executed on the server is built, just like we did before with BANanoMySQLE, BANanoMSSQLE etc. As an example..

B4X:
Sub CreateProvince(ProvinceM As Map)            'ignoredeadcode 
    'remove the auto-increment key field 
    ProvinceM.Remove("provinceid") 
    Dim rsProvinces As BANanoMySQLE 
    rsProvinces.Initialize("mydb", "provinces", "provinceid", "provinceid") 
    'add field types 
    rsProvinces.SchemaAddInt(Array("provinceid"))
    rsProvinces.SchemaAddText(Array("provincename"))
    'insert current record 
    rsProvinces.Insert1(ProvinceM)
    rsProvinces.SetCallBack("ViewProvinces", "CreateProvinceNext")
    'build the payload
    Dim payload As Map = rsProvinces.Build(False)
    'call the method from the app
    vuetify.RunMethod("SQLOnBrowser", payload)
End Sub

I guess you are still familiar with the first part of this code. As you can see, we no longer have BANano.CallInlinePHP or Db.ExecuteWait.

We build the payload with ...Build(False), and then pass this payload to SQLOnBrowser.

SQLOnBrowser is the entry point of the 1. To Server blue line above coming from the BROWSERIndex module to SHAREDIndex. SHAREDIndex contains both BANano and B4J code that "joins" the BROWSER and the SERVER part of the app.

The contents that we pass to the server are passed as a map. This needs to be converted to JSON format. So SQLOnBrowser, converts the map object we passed to JSON format and then calls a SERVER websocket function via a promise.

B4X:
'process records to the MySQL Database, receive from router
Sub SQLOnBrowser(payload As Map)            'ignoreDeadCode
    Log("BrowserIndex.MySQLOnBrowser")
    Log("payload to send...")
    Log(payload)
    'convert the payload to json
    Dim jsonPayload As String = BANano.ToJson(payload)
    'push the payload to the server
    Dim resp As String
    Dim prom As BANanoPromise = ws.RunFunctionWithResult("SQLOnServer", Array(jsonPayload))
    BANano.Await(prom)
    prom.Then(resp)
        odbc.Initialize(resp)
        'odbc.FromJSON(resp)
        'a process with an error returns -1
        If odbc.affectedRows = -1 Then
            vuetify.ShowSnackBarError("An error took place processing your request, please try again!")
            Return
        End If
        
        Select Case odbc.view
        Case "ViewDevices"
            ViewDevices.PayloadManager(odbc)
        Case "ViewLocations"
            ViewLocations.PayloadManager(odbc)
        Case "ViewProvinces"
            ViewProvinces.PayloadManager(odbc)
        Case "ViewTopics"
            ViewTopics.PayloadManager(odbc)
        Case "ViewTranTypes"
            ViewTranTypes.PayloadManager(odbc)
        Case "ViewUserDevices"
            ViewUserDevices.PayloadManager(odbc)
        Case "ViewMembers"
            ViewMembers.PayloadManager(odbc)                    
        End Select
    prom.end
End Sub

Let me explain using a graphic.

untitled_page.png


Graphic Explanation

1. From the BROWSERIndex module / any VueJS router.
2. You are performing a CRUD related call.
3. You pass a map variable that hold key values of fields and values for the record.
4. This map is passed to a method in the BROWSERINDEX module, the method is called SQLOnBrowser.
5. The map variable is converted to a JSON payload
6. A BANanoPromise is created, this passed the JSON payload to the server via a web socket call.
7. The JSON payload is received by a method on the SERVERINDEX module, this method is called SQLOnServer. This speaks to the database..
8. After the database returns the needed data, a JSON payload is returned, this could be a list of records etc etc.

This explains the journey of the blue 1. To Server and 1. FromServer lines on the first post.
 

Mashiane

Expert
Licensed User
Longtime User
Handling the JSON data from the SERVERIndex.SQLOnServer promise call

For us to handle the returned data from our jServer DB connection, we need a handler. We have created a PayloadManager sub for each of the modules we have made.

untitled_page.png


In the CreateProvince method above, there is some additional code we added, this was not necessary when we were creating BANanoVuetifyAD3 apps normally.

B4X:
rsProvinces.SetCallBack("ViewProvinces", "CreateProvinceNext")

This piece of code here is basically saying, so I have received the JSON string from the server, so what do I do next.

Remember, we only have 1 browser handler page for our BVAD3 app, BROWSERIndex and the rest of the handlers / routers were added to this single page via the code modules. These code modules have names e.g. ViewProvinces, to handle all the UX and functionalities of that module.

So here we are saying, go to the ViewProvinces code module and then call the CreateProvinceNext sub.

We need to tell our app this so that when the SQLOnServer promise returns content, it knows what to do.

So in our SQLOnBrowser call, lets look at it again..

B4X:
'process records to the MySQL Database, receive from router
Sub SQLOnBrowser(payload As Map)            'ignoreDeadCode
    Log("BrowserIndex.MySQLOnBrowser")
    Log("payload to send...")
    Log(payload)
    'convert the payload to json
    Dim jsonPayload As String = BANano.ToJson(payload)
    'push the payload to the server
    Dim resp As String
    Dim prom As BANanoPromise = ws.RunFunctionWithResult("SQLOnServer", Array(jsonPayload))
    BANano.Await(prom)
    prom.Then(resp)
        odbc.Initialize(resp)
        'odbc.FromJSON(resp)
        'a process with an error returns -1
        If odbc.affectedRows = -1 Then
            vuetify.ShowSnackBarError("An error took place processing your request, please try again!")
            Return
        End If
       
        Select Case odbc.view
        Case "ViewDevices"
            ViewDevices.PayloadManager(odbc)
        Case "ViewLocations"
            ViewLocations.PayloadManager(odbc)
        Case "ViewProvinces"
            ViewProvinces.PayloadManager(odbc)
        Case "ViewTopics"
            ViewTopics.PayloadManager(odbc)
        Case "ViewTranTypes"
            ViewTranTypes.PayloadManager(odbc)
        Case "ViewUserDevices"
            ViewUserDevices.PayloadManager(odbc)
        Case "ViewMembers"
            ViewMembers.PayloadManager(odbc)                   
        End Select
    prom.end
End Sub

The map variable that contains our query to the database is received, this is converted into JSON, SQLOnServer promise is called, this returns a JSON string.
We run .FROMJSON on this so that we can parse the JSON data received. This tells us the callback we need to execute with the data received.

For the appropriate view, we pass this to the PayloadManager.
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
What does a PayloadManager do?

A payload manager manages the payload received from the server. As an example, for provinces, if we were reading a record, the record should be displayed in our user interface. If we were retrieving a list of all provinces, the list should be displayed on a table etc. etc.

Lets look at this one for the ViewProvinces view.

B4X:
'processes returned payload data for this router
Sub PayloadManager(odbc As SHAREDODBC)
    Select Case odbc.action
    Case "LoadProvincesNext"
        Select Case odbc.OK
        Case False
            'clear content
            dtProvinces.Reload(provinces, provinces.NewList)
            dtProvinces.UpdateLoading(provinces, False)
            Dim strError As String = odbc.Error
            vuetify.ShowSnackBarError("An error took place whilst running the command. " & strError)
            Return
        End Select
        dtProvinces.Reload(provinces, odbc.Result)
        dtProvinces.UpdateLoading(provinces, False)
    Case "ReadProvinceNext"
        Select Case odbc.OK
        Case False
            Dim strError As String = odbc.Error
            vuetify.ShowSnackBarError("An error took place whilst running the command. " & strError)
            Return
        End Select
        Dim ProvinceM As Map = odbc.result.Get(0)
        'show the drawer
        provinces.SetData("dlgProvincesshow", True)
        provinces.SetData("Province", ProvinceM)
    Case "UpdateProvinceNext"
        Select Case odbc.OK
        Case False
            Dim strError As String = odbc.Error
            vuetify.ShowSnackBarError("An error took place whilst running the command. " & strError)
        Case Else
            vuetify.ShowSnackBarSuccess("The province has been updated successfully!")
            'hide modal form
            provinces.SetData("dlgProvincesshow", False)
            'load records
            provinces.RunMethod("LoadProvinces", Null)
        End Select
    Case "CreateProvinceNext"
        Select Case odbc.OK
        Case False
            Dim strError As String = odbc.Error
            vuetify.ShowSnackBarError("An error took place whilst running the command. " & strError)
        Case Else
            vuetify.ShowSnackBarSuccess("The province has been added successfully!")
            'hide modal form
            provinces.SetData("dlgProvincesshow", False)
            'Load records
            provinces.RunMethod("LoadProvinces", Null)
        End Select
    Case "DeleteProvinceNext"
        Select Case odbc.OK
        Case False
            Dim strError As String = odbc.Error
            vuetify.ShowSnackBarError("An error took place whilst running the command. " & strError)
            Return
        Case Else
            vuetify.ShowSnackBarSuccess("The province was deleted successfully!")
        End Select
        provinces.RunMethod("LoadProvinces", Null)
    End Select
End Sub

For example, LoadProvincesNext, this takes the received list of provinces and displays it on a table.

I'm still confused. Yep I understand...

Ok, lets go back a little.

In a normal BVAD3, your code would be like this..

B4X:
Sub CreateProvince(ProvinceM As Map)            'ignoredeadcode 
    'remove the auto-increment key field 
    ProvinceM.Remove("provinceid") 
    Dim rsProvinces As BANanoMySQLE 
    rsProvinces.Initialize("mydb", "provinces", "provinceid", "provinceid") 
    'add field types 
    rsProvinces.SchemaAddInt(Array("provinceid"))
    rsProvinces.SchemaAddText(Array("provincename"))
 
    'insert current record 
    rsProvinces.Insert1(ProvinceM) 
    rsProvinces.JSON = banano.CallInlinePHPWait(rsProvinces.MethodName, rsProvinces.Build(False)) 
    rsProvinces.FromJSON 
    Select Case rsProvinces.OK 
    Case False 
        Dim strError As String = rsProvinces.Error 
        vuetify.ShowSnackBarError("An error took place whilst running the command. " & strError) 
    Case Else 
        vuetify.ShowSnackBarSuccess("The province has been added successfully!") 
    'hide modal form 
        provinces.SetData("dlgProvincesshow", False) 
    'Load records 
        provinces.RunMethod("LoadProvinces", Null) 
    End Select 
End Sub

So we are just SPLITTING THE CODE by, building the first part on the BROWSER (payload), send payload to SERVER.

We execute this part on the BROWSER..

1.
B4X:
Sub CreateProvince(ProvinceM As Map)            'ignoredeadcode 
    'remove the auto-increment key field 
    ProvinceM.Remove("provinceid") 
    Dim rsProvinces As BANanoMySQLE 
    rsProvinces.Initialize("mydb", "provinces", "provinceid", "provinceid") 
    'add field types 
    rsProvinces.SchemaAddInt(Array("provinceid"))
    rsProvinces.SchemaAddText(Array("provincename"))
 
    'insert current record 
     'build the payload

2. Call SQLOnSERVER on the SERVER + get the payload and

3. Have the last part handled by the payload manager i.e

B4X:
rsProvinces.FromJSON 
    Select Case rsProvinces.OK 
    Case False 
    'clear content 
        dtProvinces.Reload(provinces, provinces.NewList) 
        dtProvinces.UpdateLoading(provinces, False)
        Dim strError As String = rsProvinces.Error 
        vuetify.ShowSnackBarError("An error took place whilst running the command. " & strError) 
        Return 
    End Select 
    dtProvinces.Reload(provinces, rsProvinces.Result)
    dtProvinces.UpdateLoading(provinces, False)

Hope it makes sense.

Ta!

Example Source code COMING SOON!!!!
 

Mashiane

Expert
Licensed User
Longtime User
BANanoVuetifyAD3 + BANAnoServer + SQLite DB CRUD running on port 55056

Here we go...

We look at creating a CRUD application using SQLite as a backend, a BANanoServer Web App running on port 55056.

Go on download now and check it out, https://github.com/Mashiane/BANanoVuetifyAD3

NB: This is part 44 of the tutorial.


 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
BANanoVuetifyAD3 + BANanoServer + MySQL DB CRUD running on port 55056

Here we go

We look at creating a CRUD application using MySQL as a backend, a BANanoServer Web App running on port 55056

Go and download now and check it out, https://github.com/Mashiane/BANanoVuetifyAD3

NB: This is part 45 of the tutorial



For MSSQL, just update the MySQL connection settings on the config.properties file.


All the best.
 
Top