This is the second part of the UI (ABMaterial) Connection. I wanted to do this one before releasing ABM 4.25 because it contains some important concepts on defining the events for B4JS in an ABMPage.
I’ve created a B4JS Demo that includes the source code for all the tutorials (so far). It will be included in the download zip.
One of the major advantages of B4JS is that you can check a lot of the users input before heading to the server. And because we have some events (like KeyDown, KeyUp) that we do not have on the server side, we can even do some ‘masking’.
This example makes such a mask for a credit card (every 4 chars a space is inserted and a check is done). It is not finished (e.g. it does not take into account if the user puts its cursor in the middle), but it shows some major concepts of B4JS.
Lets dive into the B4X code:
The B4JS class B4JSInputChecker:
<br> 'Class module Sub Class_Globals Private Page As ABMPage 'ignore, just to be able to run ABMPage functions Private ToastID As Int Private ABM As ABMaterial 'ignore, just to be able to use ABM constants End Sub 'Initializes the object. You can add parameters to this method if needed. Public Sub InitializeB4JS End Sub public Sub InputDown(Key As String) As Boolean 'Log("Down key: " & Key) Dim cardInp As ABMInput 'ignore that it is not initialized, you can't initialize one in B4JS anyway cardInp.B4JSUniqueKey = "cardInp001" Dim CardNumber As String = cardInp.B4JSText If Key = "Backspace" Then If CardNumber.SubString2(0,CardNumber.Length-1).EndsWith(" ") Then CardNumber = CardNumber.SubString2(0,CardNumber.Length - 2) cardInp.B4JSText = CardNumber CheckCard(CardNumber.Replace(" ", "")) ' consume the event Return True End If ' let the Keydown do its thing Return False End If If CardNumber.Length = 19 Then CheckCard(CardNumber.Replace(" ", "")) Return True End If If Not(IsNumber(Key)) Then ToastID = ToastID + 1 Page.B4JSShowToast("InputToast" & ToastID, "red", "Please only enter numbers!", 3000, False) ' consume the event Return True End If ' let the Keydown do its thing Return False End Sub public Sub InputUp(KeyCode As Int) As Boolean 'Log("Up keycode: " & KeyCode) Dim cardInp As ABMInput 'ignore that it is not initialized, you can't initialize one in B4JS anyway cardInp.B4JSUniqueKey = "cardInp001" Dim CardNumber As String = cardInp.B4JSText ' we down't want to raise it for the combination keys ' AltGraph, Shift, Ctrl, Alt Select Case KeyCode Case 16, 17, 18 ' consume the event Return True Case 8 ' and for the backspace, jump out too: we do not want to re-append the space ' consume the event CheckCard(CardNumber.Replace(" ", "")) Return True End Select Select Case CardNumber.Length Case 4,9,14 cardInp.B4JSText = CardNumber & " " End Select 'a valid 4012 8888 8888 1881 CheckCard(CardNumber.Replace(" ", "")) ' consume the event Return True End Sub public Sub CheckCard(CardNumber As String) 'a valid 4012 8888 8888 1881 Dim isValid As Boolean = Page.B4JSRunInlineJavascriptMethod("validateCCNum", Array As Object(CardNumber.Replace(" ", ""))) Dim btnCheck As ABMButton 'ignore btnCheck.B4JSUniqueKey = "btnCheck" ' for our setButtonCSS method we do need the real ID of the button. We can get this with the Page.B4JSGetComponentIDFromUniqueID() method! Dim ID As String = Page.B4JSGetComponentIDFromUniqueID("btnCheck") If isValid Then btnCheck.B4JSEnabled = True Page.B4JSRunInlineJavascriptMethod("setButtonCSS", Array As String(ID, "background-color: #4caf50 !important")) Else btnCheck.B4JSEnabled = False Page.B4JSRunInlineJavascriptMethod("setButtonCSS", Array As String(ID, "background-color: #F44336 !important")) End If End Sub ' every method you want to call with a B4JSOn... call MUST return a boolean public Sub InputGotFocus() As Boolean ToastID = ToastID + 1 Page.B4JSShowToast("InputToast" & ToastID, "red", "You are entering the Credit Card", 3000, False) ' consume the event Return True End Sub ' every method you want to call with a B4JSOn... call MUST return a boolean public Sub InputLostFocus() As Boolean ToastID = ToastID + 1 Page.B4JSShowToast("InputToast" & ToastID, "red", "Leaving the Credit Card field...", 3000, False) ' consume the event Return True End Sub ' every method you want to call with a B4JSOn... call MUST return a boolean public Sub CheckInput() As Boolean Dim switch1 As ABMSwitch 'ignore that it is not initialized, you can't initialize one in B4JS anyway switch1.B4JSUniqueKey = "switch001" Dim HasError As Boolean = False ToastID = ToastID + 1 If Not(switch1.B4JSState) Then Page.B4JSShowToast("SwitchToast" & ToastID, "green", "Please put the Switch to ON!", 3000, False) HasError = True End If ToastID = ToastID + 1 Dim CheckBox1 As ABMCheckbox 'ignore that it is not initialized, you can't initialize one in B4JS anyway CheckBox1.B4JSUniqueKey = "CheckBox001" If Not(CheckBox1.B4JSState) Then Page.B4JSShowToast("CheckboxToast" & ToastID, "green", "Please check the Checkbox!", 3000, False) HasError = True End If If HasError = False Then ToastID = ToastID + 1 Page.B4JSShowToast("CheckboxInput" & ToastID, "green", "All looks OK, well done!", 3000, False) End If ' consume the event Return True End Sub ' every method you want to call with a B4JSOn... call MUST return a boolean public Sub SwitchClick() As Boolean Dim switch1 As ABMSwitch 'ignore that it is not initialized, you can't initialize one in B4JS anyway switch1.B4JSUniqueKey = "switch001" ToastID = ToastID + 1 If switch1.B4JSState Then Page.B4JSShowToast("SwitchToast" & ToastID, "green", "Switch is ON", 3000, False) Else Page.B4JSShowToast("SwitchToast" & ToastID, "green", "Switch is OFF", 3000, False) End If ' consume the event Return True End Sub ' every method you want to call with a B4JSOn... call MUST return a boolean public Sub CheckBoxClick() As Boolean Dim CheckBox1 As ABMCheckbox 'ignore that it is not initialized, you can't initialize one in B4JS anyway CheckBox1.B4JSUniqueKey = "CheckBox001" ToastID = ToastID + 1 If CheckBox1.B4JSState Then Page.B4JSShowToast("CheckboxToast" & ToastID, "green", "Checkbox ON", 3000, False) Else Page.B4JSShowToast("CheckboxToast" & ToastID, "red", "Checkbox OFF", 3000, False) End If ' consume the event Return True End Sub ' every method you want to call with a B4JSOn... call MUST return a boolean public Sub RadioClick() As Boolean Dim Radio1 As ABMRadioGroup 'ignore that it is not initialized, you can't initialize one in B4JS anyway Radio1.B4JSUniqueKey = "Radio001" ToastID = ToastID + 1 Page.B4JSShowToast("RadioToast" & ToastID, "green", "Active Radio = " & Radio1.B4JSGetActive, 3000, False) ' example of setting the active radio 'If Radio1.B4JSGetActive = 0 Then ' Radio1.B4JSSetActive(2) 'End If Return True End Sub public Sub RangeOnChange(start As String, Stop As String, ConsumeEvent As Boolean) As Boolean Log("B4JS Start: " & start) Log("B4JS Stop: " & Stop) Return ConsumeEvent End Sub #if JAVASCRIPT function setButtonCSS(id, val) { $('#' + id).attr('style', val); } #End If
And creating the components in ConnectPage():
public Sub ConnectPage() ' connecting the navigation bar ABMShared.ConnectNavigationBar(page) page.Cell(1,1).AddComponent(ABMShared.BuildParagraph(page,"par1","This demo is practical example of B4JS. It uses the B4JSInputChecker B4JS class.") ) ' input Dim cardInp As ABMInput cardInp.Initialize(page, "inp1", ABM.INPUT_TEXT, "Credit Card", False, "") cardInp.B4JSUniqueKey = "cardInp001" ' special case, it has to pass at least the pressed key (ABM.B4JS_PARAM_INPUTKEY or ABM.B4JS_PARAM_INPUTKEYCODE) to it! cardInp.B4JSOnKeyDown("B4JSInputChecker", "InputDown", Array As Object(ABM.B4JS_PARAM_INPUTKEY)) cardInp.B4JSOnKeyUp("B4JSInputChecker", "InputUp", Array As Object(ABM.B4JS_PARAM_INPUTKEYCODE)) ' some focus stuff cardInp.B4JSOnGotFocus("B4JSInputChecker", "InputGotFocus", Null) cardInp.B4JSOnLostFocus("B4JSInputChecker", "InputLostFocus", Null) page.Cell(2,1).AddComponent(cardInp) ' switch Dim switch1 As ABMSwitch switch1.Initialize(page, "switch1", "ON", "OFF", False, "") switch1.B4JSUniqueKey = "switch001" switch1.B4JSOnClick("B4JSInputChecker", "SwitchClick", Null) page.Cell(3,1).AddComponent(switch1) ' checkbox Dim CheckBox1 As ABMCheckbox CheckBox1.Initialize(page, "CheckBox1", "B4JS Checkbox", False, "") CheckBox1.B4JSUniqueKey = "CheckBox001" CheckBox1.B4JSOnClick("B4JSInputChecker", "CheckBoxClick", Null) page.Cell(4,1).AddComponent(CheckBox1) ' radiogroup Dim Radio1 As ABMRadioGroup Radio1.Initialize(page, "Radio1", "") Radio1.B4JSUniqueKey = "Radio001" Radio1.AddRadioButton("radio 0", True) Radio1.AddRadioButton("radio 1", True) Radio1.AddRadioButton("radio 2", True) Radio1.SetActive(1) Radio1.B4JSOnClick("B4JSInputChecker", "RadioClick", Null) page.Cell(5,1).AddComponent(Radio1) ' range Dim range As ABMRange range.Initialize(page, "range", 10, 20, 0, 100, 1, "") range.B4JSUniqueKey = "range001" ' special case, it has to pass at least ABM.B4JS_PARAM_RANGESTART & ABM.B4JS_PARAM_RANGESTOP! range.B4JSOnChange("B4JSInputChecker", "RangeOnChange", Array As Object(ABM.B4JS_PARAM_RANGESTART, ABM.B4JS_PARAM_RANGESTOP, True)) page.Cell(6,1).AddComponent(range) ' button Dim btnCheck As ABMButton btnCheck.InitializeFlat(page, "btnCheck", "", "", "Check", "red") btnCheck.Enabled = False btnCheck.B4JSUniqueKey = "btnCheck" btnCheck.B4JSOnClick("B4JSInputChecker", "CheckInput", Null) page.Cell(7,1).AddComponent(btnCheck) ' refresh the page page.Refresh ' Tell the browser we finished loading page.FinishedLoading ' restoring the navigation bar position page.RestoreNavigationBarPosition End Sub
As you see, for every component we want to use in a B4JS class, we have to set the B4JSUniqueKey property.
We also define some events (B4JSOn…). You notice some of them have special parameters, e.g. the ABMInputs B4JSOnKeyDown event. This event MUST have at least the parameter ABM.B4JS_PARAM_INPUTKEY or ABM.B4JS_PARAM_INPUTKEYCODE to be able to work.
For the B4JSOnKeyDown event for example, we pass the ABM.B4JS_PARAM_INPUTKEY param. The order of the params is very important!
In our B4JS class, this is our method definition:
public Sub InputDown(Key As String) As Boolean<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>
Here ABM.B4JS_PARAM_INPUTKEY’s value will be put into the Key param.
You can add additional params (if needed) as for example is done in the range.B4JSOnChange event declaration.
This concludes the tutorial. ABM 4.25 is now available for download for all donators in the feedback app!
Alwaysbusy