B4J Tutorial [ABMaterial] B4JS - 03 Inline Javascript

Discussion in 'B4J Tutorials' started by alwaysbusy, Mar 6, 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 may use some typical ABM things. You can ignore them as they are just to show the result of the code in this tutorial.
    -------------------------------------------------------------------------------

    This is another one of those fantastic B4X features that I wanted in B4JS: Inline Javascript.

    Just like its big brothers, you can easily put javascript functions in a B4JS class. This last part is important: it will ONLY work in a B4JS class. But, as we will see further, you will be able to call the method in your normal ABM Page class.

    So, suppose we found a nice method in Javascript to check a credit card. In your B4JS class, you can use #If JAVASCRIPT and #End If to define a javascript region. You can add multiple methods in one block if you want.

    Code:
    Public Sub InitializeB4JS
       
    Page.B4JSRunMethod("B4JSCalculateDistance""cHECKCard"Array As String("5105105105105100"))
       
    Page.B4JSRunMethod("B4JSCalculateDistance""CheckCard"Array As String("111111"))
    End Sub

    public Sub CheckCard(cardNumber As String)
       
    Dim isValid As Boolean = Page.B4JSRunInlineJavascriptMethod("validateCCNum"Array As Object(cardNumber))
       
    If isValid Then
           
    Log("Card '" & cardNumber & "' is a valid card. Please continue...")
       
    Else
           
    Log("Card '" & cardNumber & "' is NOT valid. Please check the number...")
       
    End If
    End Sub

    #If JAVASCRIPT
    function validateCCNum(ccnum) {
       var ccCheckRegExp = /[^\d\s-]/;
        var isValid = !ccCheckRegExp.test(ccnum);
        var i;

        if (isValid) {
            var cardNumbersOnly = ccnum.replace(/[\s-]/g,"");
            var cardNumberLength = cardNumbersOnly.length;

            var arrCheckTypes = ['visa', 'mastercard', 'amex', 'discover', 'dinners', 'jcb'];
            for(i=0; i<arrCheckTypes.length; i++) {
                var lengthIsValid = false;
                var prefixIsValid = false;
                var prefixRegExp;

                switch (arrCheckTypes[i]) {
                    case "mastercard":
                        lengthIsValid = (cardNumberLength === 16);
                        prefixRegExp = /^5[1-5]/;
                        break;

                    case "visa":
                        lengthIsValid = (cardNumberLength === 16 || cardNumberLength === 13);
                        prefixRegExp = /^4/;
                        break;

                    case "amex":
                        lengthIsValid = (cardNumberLength === 15);
                        prefixRegExp = /^3([47])/;
                        break;

                    case "discover":
                        lengthIsValid = (cardNumberLength === 15 || cardNumberLength === 16);
                        prefixRegExp = /^(6011|5)/;
                        break;

                    case "dinners":
                        lengthIsValid = (cardNumberLength === 14);
                        prefixRegExp = /^(300|301|302|303|304|305|36|38)/;
                        break;

                    case "jcb":
                        lengthIsValid = (cardNumberLength === 15 || cardNumberLength === 16);
                        prefixRegExp = /^(2131|1800|35)/;
                        break;

                    default:
                        prefixRegExp = /^$/;
                }

                prefixIsValid = prefixRegExp.test(cardNumbersOnly);
                isValid = prefixIsValid && lengthIsValid;

                // Check if we found a correct one
                if(isValid) {
                    break;
                }
            }
        }

        if (!isValid) {
            return false;
        }

        // Remove all dashes for the checksum checks to eliminate negative numbers
        ccnum = ccnum.replace(/[\s-]/g,"");
        // Checksum ("Mod 10")
        // Add even digits in even length strings or odd digits in odd length strings.
        var checksum = 0;
        for (i = (2 - (ccnum.length % 2)); i <= ccnum.length; i += 2) {
            checksum += parseInt(ccnum.charAt(i - 1));
        }

        // Analyze odd digits in even length strings or even digits in odd length strings.
        for (i = (ccnum.length % 2) + 1; i < ccnum.length; i += 2) {
            var digit = parseInt(ccnum.charAt(i - 1)) * 2;
            if (digit < 10) {
                checksum += digit;
            } else {
                checksum += (digit - 9);
            }
        }

        return (checksum % 10) === 0;
    }
    #End If
    The result in the browsers console:
    Code:
    Card '5105105105105100' is a valid card. Please continue...
    Card '111111' is NOT valid. Please check the number...
    Pretty cool no? :)

    A couple of things we see here in the code (besides the #if JAVASCRIPT part.

    1. Calling a javascript function in your B4JS code using Page.B4JSRunInlineJavascriptMethod:
    Code:
    Dim isValid As Boolean = Page.B4JSRunInlineJavascriptMethod("validateCCNum"Array As Object(cardNumber))
    It is VERY important (unlike we are used in B4J, that the method name (here validateCCNum) matches the case. e.g. VAlidateCCNum will NOT work!

    2. Calling a B4JS function in your B4JS code using Page.B4JSRunMethod:
    Code:
    Page.B4JSRunMethod("B4JSCalculateDistance""cHECKCard"Array As String("5105105105105100"))
    And we're back on familiar B4X ground :) The case of the method (or class) does not matter as all is lowercased anyway. Why do we have to mention the class, I hear you think. Well this is because we can call a method from ANOTHER B4JS class too!

    And moreover, we can also call these methods in our normal ABM webpage!
    Code:
    sub ConnectPage()
     ...
    ' method 1: calling our own B4JS sub and handeling the result on thebrowser side
       page.B4JSRunMethod("B4JSCalculateDistance""cHECKCard"Array As String(CardNumber))
      
       
    ' method 2: directly calling the Javascript function and handeling the result on the server side
       Dim isValid As Boolean = page.B4JSRunInlineJavascriptMethod("validateCCNum"Array As Object(CardNumber))
       
    If isValid Then
           
    Log("Server Card '" & CardNumber & "' is a valid card. Please continue...")
       
    Else
           
    Log("Server Card '" & CardNumber & "' is NOT valid. Please check the number...")
       
    End If
       ...
    End Sub
    So the result of method 1 (in the Browser log)
    Code:
    Card '5105105105105100' is a valid card. Please continue...
    Card '111111' is NOT valid. Please check the number...
    And the result of method 2 (in the B4J log)
    Code:
    Server Card '5105105105105100' is a valid card. Please continue...
    In the next tutorial (04 - Running Javascript on the server side) I'll show how you can even run this on the server side, not even needing a browser open. :p

    A final note: #if JAVASCRIPT regions do not really belong to the class. They are shared between all B4JS classes you create.

    This concludes this tutorial.

    Alwaysbusy
     
    Last edited: Mar 6, 2018
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