B4J Tutorial [ABMaterial] B4JS - 01 Getting Started

Discussion in 'B4J Tutorials' started by alwaysbusy, Mar 5, 2018.

  1. alwaysbusy

    alwaysbusy Expert Licensed User

    See for a B4JS introduction: https://www.b4x.com/android/forum/threads/abmaterial-b4js-0-9.90249/

    Note: for this tutorial, I'll use some typical ABM things. You can ignore them as they are just to show the result of the code in this tutorial.
    -------------------------------------------------------------------------------
    In this first tutorial, we are going to create a killer method to calculate the distance between two GEO locations. There are better ways to do so, but for demos sake...

    Creating a B4JS class is very simple. Just use the menu in B4J and add a Standard Class.
    Code:
    'Class module
    Sub Class_Globals

    End Sub

    Public Sub Initialize
     
    End Sub
    First thing we MUST do is renaming the Initialize method to InitializeB4JS. This is because the transpiler uses this method name to determine it has to translate this class to Javascript.

    This InitializeB4JS method can NOT have parameters!

    Now we can start adding our code, just as usual in B4J. As almost the whole Core library of B4J is available, this is pretty forward. Except from the ABM methods, this could easily be seen as B4J.

    Code:
    'Class module
    Sub Class_Globals
       
    ' use public or dim if you want to share this variable over ALL B4JS classes
       ' use private if only within this class
       Dim ToKM As Double = 1.609344
       
    Dim ToMiles As Double = 0.8684
     
       
    ' to access the constants
       Public ABM As ABMaterial 'ignore
       ' so we can use an msgbox
       Public Page As ABMPage 'ignore, just to be able to run ABMPage functions 
    End Sub

    'Initializes the object. You can NOT add parameters to this method.
    'MUST be called InitializeB4JS is automatically called when using this class
    Public Sub InitializeB4JS
     
    End Sub

    public Sub CalcDistance(Lat1 As Double, Lon1 As Double, Lat2 As Double, Lon2 As Double, Unit As String)
       
    Dim theta As Double
       
    Dim Distance As Double
       theta = Lon1 - Lon2
       Distance = 
    Sin(deg2rad(Lat1)) * Sin(deg2rad(Lat2)) + Cos(deg2rad(Lat1)) * Cos(deg2rad(Lat2)) * Cos(deg2rad(theta))
       
    ' logging some intermediate value
       Log("Distance = " & Distance)
       Distance = 
    ACos(Distance)
       Distance = rad2deg(Distance)
       
    ' logging some intermediate value
       Log("Distance = " & Distance)
       Distance = Distance * 
    60 * 1.1515
       
    ' if we would use Page.Msgbox here, we would see in the logs an error: msgbox is NOT supported in B4JS!
       ' we must use the B4JS equivalent method Page.B4JSMsgbox
       Select Case Unit.ToUpperCase
           
    Case "K"
               
    Page.B4JSMsgbox("msgbox""The distance is " & (Distance * ToKM) & " kilometers!""Tutorial""OK"False, ABM.MSGBOX_POS_CENTER_CENTER, "")
           
    Case "N"
               
    Page.B4JSMsgbox("msgbox""The distance is " & (Distance * ToMiles) & " miles!""Tutorial""OK"False, ABM.MSGBOX_POS_CENTER_CENTER, "")
           
    Case Else
               
    Page.B4JSMsgbox("msgbox""No idea what you are doing :-)""Tutorial""OK"False, ABM.MSGBOX_POS_CENTER_CENTER, "")
       
    End Select
    End Sub

    ' some helper methods
    Sub deg2rad(Deg As Double) As Double
       
    Return Deg * cPI / 180
    End Sub

    Sub rad2deg(Rad As Double) As Double
       
    Return Rad * 180 / cPI
    End Sub
    VERY IMPORTANT!!!
    Depending on how you declare the variable in Class_Globals, a variable is shared between class instances or not:

    This concept becomes very important when we start using ABMComponents because when you attach a B4JSOn... event to an ABMComponent, it gets its own instance of your class. The Public/Dim variables will be shared among all the components using this B4JS Class

    To use our new method, I'll make a button in ConnectPage() on the ABM page (this will be explained in a future tutorial) and when we click, we do a calculation:
    Code:
    ' tutorial 1
       Dim btn As ABMButton
       btn.InitializeFlat(
    page"btn""""""Calculate""")
       btn.B4JSUniqueKey = 
    "btn001"
       
    ' define the B4JS OnClickedEvent
       btn.B4JSOnClick("B4JSCalculateDistance""CalcDistance"Array As Object(32.9697, -96.8032229.46786, -98.53506"K"))
       
    page.Cell(2,1).AddComponent(btn)
    Alternative, not using an ABMButton but calling our method directly:
    Code:
    page.B4JSRunMethod("B4JSCalculateDistance""CalcDistance"Array As Object(32.9697, -96.8032229.46786, -98.53506"K"))
    So let's check our results:
    [​IMG]

    1. In the browsers log we see our two intermediate log() calls.
    2. the solution to our call is shown in a message box.

    But in the B4J log we also see that the normal btn_Click event is raised. That is not what we want!

    To avoid this, we make a simple change to our CalcDistance method. We return a boolean true: this is saying 'consume the click on the browser side and don't go to the server'.
    Code:
    public Sub CalcDistance(Lat1 As Double, Lon1 As Double, Lat2 As Double, Lon2 As Double, Unit As StringAs Boolean
       ...
       
    ' important, if we do not want to raise the servers btn_click events, we must return true
       Return True
    End Sub
    And hooray, our server is not contacted any more! :)
    [​IMG]

    Ultimate proof we are not contacting the server for this code. I've stopped the server app and I can still use the button:
    [​IMG]

    This concludes the first tutorial.

    For those interested in the Javascript generated for our class, here it is:
    Code:
    var_tokm=1.609344;
    var _tomiles=
    0.8684;
    var _abm;
    var _
    page;
    function b4js_b4jscalculatedistance() {
         var self;
         this.initializeb4js=function(){
              self=this;
              
    try {
              
    }
              catch(err) {
                   console.log(err.message + ' ' + err.stack);
              }
         };
         this.calcdistance=function(_lat1,_lon1,_lat2,_lon2,_unit){
              try {
                   var _theta=0;
                   var _distance=0;
                   _theta = _lon1-_lon2;
                   _distance = (Math.sin(self.deg2rad(_lat1)))*(Math.sin(self.deg2rad(_lat2)))+(Math.cos(self.deg2rad(_lat1)))*(Math.cos(self.deg2rad(_lat2)))*(Math.cos(self.deg2rad(_theta)));
                   console.log("Distance = "+_distance);
                   _distance = (Math.acos(_distance));
                   _distance = self.rad2deg(_distance);
                   console.log("Distance = "+_distance);
                   _distance = _distance*60*1.1515;
                   switch ("" + _unit.toUpperCase()) {
                        case "" + "K":
                             var _b4js_returnname="msgbox";
                             b4js_msgbox("default","Tutorial","The distance is "+(_distance*_tokm)+" kilometers!","OK",'swal2pos-cc', false);;
                             break;
                        case "" + "N":
                             var _b4js_returnname="msgbox";
                             b4js_msgbox("default","Tutorial","The distance is "+(_distance*_tomiles)+" miles!","OK",'swal2pos-cc', false);;
                             break;
                        default:
                             var _b4js_returnname="msgbox";
                             b4js_msgbox("default","Tutorial","No idea what you are doing :-)","OK",'swal2pos-cc', false);;
                             break;
                   }
                   self.testjson();
                   callAjax("https://jsonplaceholder.typicode.com/posts/1","GET","jsonp", "","myJob1", true,"b4jscalculatedistance");
                   return true;
              }
              catch(err) {
                   console.log(err.message + ' ' + err.stack);
              }
         };
        
         this.deg2rad=function(_deg){
              try {
                   return _deg*Math.PI/180;
              }
              catch(err) {
                   console.log(err.message + ' ' + err.stack);
              }
         };
         this.rad2deg=function(_rad){
              try {
                   return _rad*180/Math.PI;
              }
              catch(err) {
                   console.log(err.message + ' ' + err.stack);
              }
         };
    };
    Alwaysbusy
     
    Last edited: Mar 8, 2018
  2. Mashiane

    Mashiane Expert Licensed User

    I know its early stages, but does this mean at some stage in the future one would be able to completely develop ABM apps without a constant connection to the server?

    Reason I'm asking, I was faced with developing an app that will work under-ground for miners and thought of ABM then due to the constant needed internet connection and a server, wrote something in B4A. #Just Curious.
     
    joulongleu likes this.
  3. alwaysbusy

    alwaysbusy Expert Licensed User

    No. ABM will always require a jetty server. As stated above, having all your business logic on the browser side is a very, very bad idea security wise.
     
    joulongleu, magi6162 and Mashiane like this.
  4. alwaysbusy

    alwaysbusy Expert Licensed User

    For those interested in the Javascript generated for our class, I've wrapped the Msgbox method so it can be done with one call. Makes the JS a lot shorter :)
     
    joulongleu likes this.
  5. alwaysbusy

    alwaysbusy Expert Licensed User

    If forgot to explain a very important part, so I repeat it here:

    VERY IMPORTANT!!!
    Depending on how you declare the variable in Class_Globals, a variable is shared between class instances or not:

    use Public or Dim if you want to share this variable over ALL B4JS classes
    use Private if only within this class
    This concept becomes very important when we start using ABMComponents because when you attach a B4JSOn... event to an ABMComponent, it gets its own instance of your class. The Public/Dim variables will be shared among all the components using this B4JS Class.
     
    mindful likes this.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice