Banano and B4J

@Alwaysbusy

I’m gonna start testing your Banano library for a web app I have on the steps, a rather large system for hotels and lodging.

How easy is it to integrate javascript components like fullcalendar.io?
I need a timeline scheduler for my project, and this component has a nice one.

I also am guessing that to access a database, you need to do this via a REST Api?

/Ronny

@Varandor

Sure. Adding components is easy in BANano using the CustomView. Here is a demo to get you started (the component has a lot of features, so this is just a basic example). If you have problems implementing a certain part of their API, let me know. I here use a BANanoFetch to get the events from a static json file, but this can be from a REST Api call too.

http://gorgeousapps.com/CalendarDemo.zip

Alwaysbusy

They are in the zip in the folder /Files. I just renamed the main.min.js and main.min.css files from the download with the prefix calendar because ‘main’ sounded weird :wink:

Are you running it on a WebServer? (not by just opening the .html file from disk from your browser, that does not work as a fetch does require a webserver).

Easiest I found is running this plugin in your chrome Browser for testing:

In Chrome, Press F12 to bring up the Dev console to give you a clue what went wrong (post a screenshot maybe)

Still, it is weird that you get a blank page. This is what I get when I double click on the .html file:

What do you see when you check the console and network tab in Chrome? Maybe I forgot something in the zip :thinking:

Do you see errors from the BANano transpiler in the logs in B4J?

The B4J logs show a lot of BANano transpiler errors.

The only thing I can think of is that you are not using the latest BANano libraries:

image

Latest version of BANano: http://gorgeousapps.com/BANano6.11.zip

Looks fine. Real puzzle but we will get there

In your logs I see missing CSS and JS files too. Can you copy the complete log in a .txt file? And maybe run in Debug mode instead of Release.

image

It looks like it just does not find the BANanoSkeleton library (is it in the B4J Additional Libraries folder?)

Ok, now retry it in release mode. If it does not work, send me the complete logs.

That is going to be it probably. BANanoLibraries need to be there, not in the main B4J Libraries folder. That is the place where the Transpiler looks for them.

Cool! I’ll add an entry in the BANano download section on the B4J forum about where BANanoLibraries have to be placed.

EDIT, it was there in the Getting Started section but I’ve put it in bold :wink:

1 Like

maybe a dumb question, but can I use databases like in abmaterial, or du I have to have an api for that?

You can use a database in the browser’s Local Storage (BANanoSQL) that allows you to use SQL queries like this:

SQL.OpenWait("SQL", "bananodb")
 
SQL.ExecuteWait("CREATE TABLE IF NOT EXISTS flights (flightNo INT, fromCity STRING, toCity STRING, isInTheAir BOOL)", Null)
Dim ret As List = SQL.ExecuteWait("SELECT COUNT(*) AS myCount FROM flights;", Null)
Dim MyCount As Int = SingleResult(ret, "myCount")
Log("MyCount Before: " & MyCount)
MyCount = MyCount + 1
SQL.ExecuteWait("INSERT INTO flights (flightNo, fromcity, toCity, isInTheAir) VALUES (?, ?, ?, ?)", Array(MyCount, "Brussels", "Paris", True))

for more info:

There is also a BANanoLibrary on the forum here that uses php to connect with MySQL and other databases.

ok, thanks

@Alwaysbusy

I am looking at BANano+BANanoServer now. Please tell me if I understand this correctly. Because
if I do, I think this is awesome :slight_smile:

BANanoServer is the only webserver I need right, no need for an extra webserver to access the app?

SERVERpage:

Here I can have all my db access and return data to BROWSERPage? So in prinsippal
coding like any other B4J app with access to my classes and stuff.

BROWSERPage:

Is the BANano client page, and I can have all my BANano logic here. Basically build my
gui in theese kind of pages.

SHAREDCode:
I think I get this, but do you have an example of what you have been using this for?

Is there meant to be a 1:1 relationship between SERVERpage and SERVERpage?

Correct. This is a full blown stand-alone Jetty server (must run on a VPS)

Exactly. You may look a bit to this like this serves as e.g. node.js where you can even access the hardware, a database, do some MQTT or Bluetooth stuff, etc. In short, everything a normal B4J app can do. One could for example have a Raspberry Pi that regulates the temperature in your home, running the server part. And from any browser in the world, you can connect to this Jetty server and change the temperature.

Correct. You get the best of both worlds using only one programming language: B4J!

This is just convenient as a lot of ‘logic’ may be the same on both the server (B4J Java) and the Browser side (Javascript). For example a class that holds the structure of a database record:

' a very generic record definition that can be used for about anything

Sub Class_Globals
	Public UUID As String ' must be a UUID/GUID to allow for syncing	
	Public LinkUUID As String ' must be a UUID/GUID to allow for syncing
	Public RecordType As Int ' to identify the type of record
	Public Created As String '
	Public LastModified As String '
	Public Status As Int
	
	Public Strings(SHAREDSyncDB.MAX_STR) As String
	Public Numbers(SHAREDSyncDB.MAX_NUM) As Double
		
	Public const STATUS_UNDEFINED As Int = 0
	Public const STATUS_NEW As Int = 1
	Public const STATUS_UPDATED As Int = 2
	Public const STATUS_DELETED As Int = 3
	
	Private EmptySTR As List
	Private EmptyNUM As List
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
	EmptySTR.Initialize
	For i = 0 To SHAREDSyncDB.MAX_STR - 1
		EmptySTR.Add("")
	Next
	EmptyNUM.Initialize
	For i = 0 To SHAREDSyncDB.MAX_NUM - 1
		EmptyNUM.Add("")
	Next
End Sub

Public Sub ToMapJSON() As Map
	' keys are lowercased!
	Dim m As Map
	m.Initialize
	m.Put("uuid", UUID)
	m.Put("linkuuid", UUID)
	m.Put("recordtype", RecordType)
	m.Put("created", Created)
	m.Put("lastmodified", LastModified)	
	m.Put("status", Status)
	m.Put("strings", Strings)
	m.Put("numbers", Numbers)	
	Return m
End Sub

public Sub FromMapJSON(m As Map)
	' keys are lowercased!
	UUID = m.GetDefault("uuid", "")
	LinkUUID = m.GetDefault("linkuuid", "")
	RecordType = m.GetDefault("recordtype", 0)
	Created = m.GetDefault("created", "2000-01-01T00:00:00")	
	LastModified = m.GetDefault("lastmodified", "2000-01-01T00:00:00")
	Status = m.GetDefault("status", STATUS_UNDEFINED)
	Strings = m.GetDefault("strings", EmptySTR)
	Numbers = m.GetDefault("numbers", EmptyNUM)	
End Sub

public Sub FromMapRECORD(m As Map)
	UUID = m.GetDefault("uuid", "")
	LinkUUID = m.GetDefault("linkuuid", "")
	RecordType = m.GetDefault("recordyype", 0)
	Created = m.GetDefault("created", "2000-01-01T00:00:00")
	LastModified = m.GetDefault("lastmodified", "2000-01-01T00:00:00")	
	Status = m.GetDefault("status", STATUS_UNDEFINED)
	For i = 0 To SHAREDSyncDB.MAX_STR - 1
		Strings(i) = m.GetDefault("s" & i, "")
	Next
	For i = 0 To SHAREDSyncDB.MAX_NUM - 1
		Numbers(i) = m.GetDefault("d" & i, 0.0)
	Next
End Sub

public Sub ToListRECORD(ForInsert As Boolean) As List
	Dim l As List
	l.Initialize
	If ForInsert Then
		l.Add(UUID)
	End If
	l.Add(LinkUUID)
	l.Add(RecordType)
	If ForInsert Then
		Created = SHAREDSyncDB.LongToDateTime(DateTime.Now)
		l.Add(Created)
	End If			
	l.Add(LastModified)
	l.Add(Status)
	For i = 0 To SHAREDSyncDB.MAX_STR - 1
		l.Add(Strings(i))
	Next
	For i = 0 To SHAREDSyncDB.MAX_NUM - 1
		l.Add(Numbers(i))
	Next
	If ForInsert = False Then
		l.Add(UUID)
	End If
	Return l
End Sub

Instead of having to write such a class for the server, and an identical one for the browser, they can both share this code. For the Server it will be compiled to Java by B4J, and for the browser it will be Transpiled to Javascript by BANano. The usage of this class is the same for both.

Moreover, in such a class you can use #If B4J:

So say, in a SHAREDClass, there is something specific for the Server, you can do this:

public Sub UPDATEIsSyncedWait()
	Dim Query As String
	#if B4J
		Try
			' in case of the server, it is the queue we have to update
			Query = $"UPDATE tQueue SET queuestatus=${SYNC_DONE} WHERE queuestatus=${SYNC_LOCKED}"$
			SQL.ExecNonQuery2(Query, Null)
		Catch
			Log(LastException)
		End Try
	#else
	    ' in case of the browser, we update the status of the sync in tRecords
		Query = $"UPDATE tRecords SET syncstatus=${SYNC_DONE} WHERE syncstatus=${SYNC_TODO}"$	
		SQL.ExecuteWait(Query, Null)	
	#End If		
End Sub

Probably a typo and you mean BROWSERPage/SERVERPage, but this is how it is:

(I’ve named them here Page and Class to distingush, but of course in reality both are just B4J classes)

  1. Every BROWSERPage (this is a page with WebSockets) must have a 1:1 to a SERVERPage (who also has a WebSocket)
  2. Every other BROWSERClass (not a WebSocket entry point, but e.g. a helper class) does not need a SERVERClass
  3. Same, You can have helper SERVERClasses and modules that do not have a BROWSERClass equivalent. (for example just a REST API hander).

The key here is the Websocket. If it has a Websocket entry point in the browser class then it means it wants to talk with its server equivalent, who also has a Websocket entry point.

These two page can talk with each other, as a WebSocket is bi-directional. So the SERVERPage can call a method in a BROWSERPage, and the other way around.

For example a BROWSERPage can insert some info from a DB record just by calling the method on the SERVERPage:

In SERVERPage the definition:

Sub INSERTSomethingInDB(Something...) as Boolean
    ' normal B4J stuff to run an insert query in a database

    Return successOrNot
End Sub

In BROWSERPage the call:

Dim value As Int = 0
Dim prom As BANanoPromise = ws.RunFunctionWithResult("INSERTSomethingInDB", Array(Something...))
prom.Then(value)
        Log("SERVER insert a success " & value)
prom.end

Equally, the SERVERPage can make a call e.g. to find out the user language the Browser is to the BROWSERPage:

In BROWSERPage the definition:

Sub GetBrowserLanguage() as String
     Return BANano.Navigator.GetField("language").Result
End Sub

In SERVERPage the call:

Dim fut As Future = ws.RunFunctionWithResult("GetBrowserLanguage", Null)
ws.Flush
Log("BROWSER says language is =" & fut.Value)

In summary:

The SERVER prefix lets the Transpiler know it has to be compiled for Java, not Javascript
The BROWSER prefix lets the Transpiler know it has to be transpiled to Javascript (so can only contain BANano compatible code)
The SHARED prefix lets the Transpiler know it has to be compiled to Java AND to JavaScript (contains BANano compatible code and #If B4J if some parts are for the SERVER only).

Alwaysbusy

Hah, this system is just awesome, thank you for the detailed explanation.

I was a bit intimidated at first, but the more I dig into the banano/b4j universe, the more
awesome it gets.

I am now thinking that I will switch over to use this system for my next project.

Is banano a system I can count on to exist in the forseeable future?

Absolutely! Both BANano and ABM are used and further developed in-house in my day job. As ABM is mostly considered a finished product, I will probably this year even Open Source it. BANano not yet ready for Open Source as I want to hold control over its development for the moment, but this also will happen one day.

In any case, Erel receives the source code for both on a regular basis. He holds in his ‘vault’ in case something serious would happen to me. In that case he has full authority to do with the source code as he wants, so probably making it accessible for everyone, guaranteeing everyone who works with it can continue to do so.

Alwaysbusy

1 Like

awesome, count me in as a new patron later today :grinning::sunglasses:

1 Like