B4J Question BANano read/get content of SKTextBox

Declan

Well-Known Member
Licensed User
Longtime User
I am using the following code to read the text within a SKTextBox:
B4X:
Sub btnLogIn_Click (event As BANanoEvent)
    Log("Login Button Clicked")
   
    Dim username As String
    username = txtUserName.Text
   
    Log("User Name: "&username)
End Sub
The txtUserName is declared in Process_Globals:
B4X:
Private txtUserName As SKTextBox  'ignore
When I click on btnLogIn_Click (event As BANanoEvent)
I receive the following error in the browser:
B4X:
app1588082829561.js:2 Uncaught TypeError: Cannot read property 'gettext' of undefined
    at banano_myapp.btnlogin_click (app1588082829561.js:2)
    at HTMLButtonElement.<anonymous> (app1588082829561.js:2)
    at HTMLButtonElement.<anonymous> (app1588082829561.js:2)
    at HTMLButtonElement.a (app1588082829561.js:2)
 

Declan

Well-Known Member
Licensed User
Longtime User
This is an edited version of your demo WithoutRouter:
I am using this to "get-my-head-around" BANano.
It also makes sense that I can later add languages - we have 11 official languages in SA.
Zip file is too large, here are:
Main:
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
    #IgnoreWarnings: 16, 10, 14, 15   
#End Region

Sub Process_Globals
    Private BANano As BANano 'ignore
    
    Private sticky As Int = -1
    
    Public SKNavigationBar1 As SKNavigationBar 'ignore
    Private SKContainer1 As SKContainer 'ignore
        
    Private CurrentPageName As String
    Private UniqueID As Int
    
    ' shortcut for BANano.Window
    Public Window As BANanoWindow
    
    Private btnLogIn As SKButton 'ignore
    Private txtUserName As SKTextBox  'ignore
    Private txtPassWord As SKTextBox 'ignore
    Private lblLogInError As SKLabel 'ignore
End Sub

Sub AppStart (Form1 As Form, Args() As String)   
    
    'txtUserName.Initialize(Me, "txtUserName", 1)
        
    ' you can change some output params here
    BANano.Initialize("BANano", "LeadGurus", DateTime.Now)
    BANano.HTML_NAME = "index.html"
    BANano.JAVASCRIPT_NAME = "app" & DateTime.Now & ".js"
    
    BANano.Header.Title="Lead Gurus"
        
    BANano.TranspilerOptions.ExternalTestConnectionServer = "http://leadgurus.co.za"
    BANano.TranspilerOptions.MinifyOnline = True
        
    BANano.Header.AddCSSFile("style.css")
    
            
    ' start the build
    BANano.Build(File.DirApp)
    
        
    ExitApplication
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

' HERE STARTS YOUR APP
Sub BANano_Ready()   
    ' Loading our base framework in which we will load the pages
    BANano.GetElement("#body").SetStyle($"{"background-color": "ghostwhite"}"$)
    ' We don't have any javascript files to load in this example, so we can just use the body tag.
    ' If you do have javascript files to load, then doing this will replace the <script> lines too, so be careful!
    ' In that case, add a <div> first to body and load your layouts in this new div.
    BANano.LoadLayout("#body","BaseLayout")
    
SKNavigationBar1.SetStyle($"{"width":"2000px","height":"50px","background":"blue","border-radius":"3px"}"$)

'    btnLogIn.Style = $"{"width":"100px","height":"50px","background":"green","border-radius":"3px"}"$
    

    ' Fill menu with empty strings.  They will be filled later when the language file is loaded
    SKNavigationBar1.AddMenu("Links", "")
    SKNavigationBar1.AddMenu("NearPlaces", "")
    SKNavigationBar1.AddMenu("Prices", "")
    SKNavigationBar1.AddMenu("Services", "")
    SKNavigationBar1.AddMenu("Console", "")
    SKNavigationBar1.AddMenu("Home", "")
        
    ' Load the layout.  We do not load the texts here (as we the async (promise) method HTTPRequests.LoadLanguageFile()
    ' Will fill in the text when it has finished downloading the corresponding .json file
    NavigateTo("Home", False)
        
    ' lets set the page in the users browser language (if it is "nl", "fr" or "en" else just pick "en")
    Dim browserLanguage As String = BANano.Navigator.Language.ToLowerCase
    If browserLanguage.StartsWith("en") = False And browserLanguage.StartsWith("fr") = False And browserLanguage.StartsWith("nl") = False Then
        browserLanguage = "en"
    Else
        browserLanguage = browserLanguage.SubString2(0,2)
    End If   
    
    ' Loading the translations: note this is async, so the code will just continue
    HTTPRequests.LoadLanguageFile("assets/" & browserLanguage & ".json")   
    
    ' The scrolling navigation bar callback. Note: AddEventListener requires the eventname without the 'on' prefix!
    Window.AddEventListener("scroll", BANano.CallBack(Me, "OnScroll", Null), True)   
    
    ' We also want to catch the browsers buttons so we can load the correct page from the history
    ' Note: AddEventListener requires the eventname without the 'on' prefix!
    Dim event As Map
    Window.AddEventListener("popstate", BANano.CallBack(Me, "OnPopState", event), True)
    
    

End Sub

Sub OnScroll() 'ignore
    Dim NavBar As BANanoElement    = BANano.GetElement("#sknavigationbar1")
    ' Just do it the first time to get the initial top offset.
    If sticky = -1 Then
        sticky = NavBar.OffsetTop
    End If   
    If Window.PageYOffset >= sticky Then
        ' Make it sticky if our offset is bigger than sticky
        NavBar.AddClass("sticky")
    Else
        ' Remove the stickyness
        NavBar.RemoveClass("sticky")
    End If   
End Sub

Sub OnPopState(event As Map) 'ignore
    ' Get the current state
    Dim state As Map = event.Get("state")
    If state = Null Then
        ' We are back at the homepage, so load it
        NavigateTo("Home", True)
    Else
        ' Get the state (history)
        Dim CurrentState As String = state.Get("currentState")
        ' Load the new layout and the texts
        NavigateTo(CurrentState, True)       
    End If
End Sub

Sub SKNavigationBar1_Click (event As BANanoEvent, menu As String)
    Select Case menu
        Case "nl", "fr", "en"
            ' Loading the new translations
            '  Will fill in the text when it has finished downloading the corresponding .json file
            HTTPRequests.LoadLanguageFile("assets/" & menu & ".json")
            Return
        Case Else
            ' Load the new layout and the texts
            NavigateTo(menu, True)
            
            ' Add to the history for the browser buttons
            BANano.History.PushState(CreateMap("currentState": menu), Null)
            SKNavigationBar1.CloseDrawerMenu
    End Select   
End Sub

public Sub NavigateTo(pageName As String, withTexts As Boolean)
    CurrentPageName = pageName.ToLowerCase
    ' Because Loading a layout requires a quoted string and not a variable, we must use a select case here
    ' UniqueID = BANano.LoadLayoutArray("#skcontainer1", CurrentPageName, True) would NOT work!
    '
    ' We also use LoadLayoutArray so we can use the GetViewFromLayoutArray() method in LoadTexts
    Select Case CurrentPageName
        Case "home":
            UniqueID = BANano.LoadLayoutArray("#skcontainer1", "Home", True)
        Case "console":
            UniqueID = BANano.LoadLayoutArray("#skcontainer1", "Console", True)
        Case "services":
            UniqueID = BANano.LoadLayoutArray("#skcontainer1", "Services", True)
        Case "prices"
            UniqueID = BANano.LoadLayoutArray("#skcontainer1", "Prices", True)
        Case "nearplaces"
            UniqueID = BANano.LoadLayoutArray("#skcontainer1", "NearPlaces", True)
        Case "links"
            UniqueID = BANano.LoadLayoutArray("#skcontainer1", "Links", True)
    End Select
    
    If withTexts Then
        LoadTexts
    End If
            
    ' Go to the top of the page
    Window.ScrollTo(0,0)
End Sub

public Sub LoadTexts()
    Dim Strings As Map = HTTPRequests.Strings.Get(CurrentPageName)
    
    ' For all the keys in the json map
    For Each key As String In Strings.Keys
        Dim prefix As String = key.SubString2(0,3)
        ' We use the prefix to find out what kind of Custom View it is.
        Select Case prefix
            Case "lbl"               
                Dim lbl As SKLabel = BANano.GetViewFromLayoutArray(Me,CurrentPageName, key,UniqueID)
                lbl.Text = Strings.Get(key)       
            Case "lst"
                Dim lst As SKList = BANano.GetViewFromLayoutArray(Me,CurrentPageName, key,UniqueID)
                lst.Clear
                Dim itemsStr As String = Strings.Get(key)
                Dim items() As String = BANano.Split(";", itemsStr)
                For i = 0 To items.length - 1
                    lst.AppendToList(items(i), Null, False)
                Next       
        End Select
    Next   
End Sub


Sub btnLogIn_Click (event As BANanoEvent)
    Log("Login Button Clicked")
    
    Dim username As String
    username = txtUserName.Text
    
    Log("User Name: "&username)
End Sub

Sub txtUserName_Change (event As BANanoEvent)
    
End Sub

HTTPRequests:
B4X:
'Static code module
Sub Process_Globals
    Public BANano As BANano
    Public Strings As Map   
End Sub

public Sub LoadLanguageFile(Url As String) 'ignore
    ' We make a new promise
    Dim promise As BANanoPromise 'ignore
    ' Some vars to hold our results
    Dim json As String
    Dim error As String
 
    ' Call the http request
    promise.CallSub(Me, "DoHTTPForUrl", Array(Url))
 
    promise.Then(json)
        ' We got it!
        Strings = BANano.FromJson(json)
        ' Get the menu part
        Dim menu As Map = Strings.Get("menu")
        ' We use SetMenu here to replace the texts, not AddMenu
        Main.SKNavigationBar1.SetMenu("Links", menu.Get("Links"))
        Main.SKNavigationBar1.SetMenu("NearPlaces", menu.Get("NearPlaces"))
        Main.SKNavigationBar1.SetMenu("Prices", menu.Get("Prices"))
        Main.SKNavigationBar1.SetMenu("Services", menu.Get("Services"))
        Main.SKNavigationBar1.SetMenu("Console", menu.Get("Console"))
        Main.SKNavigationBar1.SetMenu("Home", menu.Get("Home"))
        ' Use the new translations on the current page
        Main.LoadTexts
    promise.Else(error)
        Log(error)   
    promise.end
End Sub

public Sub DoHTTPForUrl(Url As String) As String 'ignore
    ' Defining a XMLHttpRequest object
    Dim Request As BANanoObject
    Request.Initialize2("XMLHttpRequest", Null)
    
    ' Running a get
    Request.RunMethod("open", Array("GET", Url))
        
    ' Defining the onload and onerror callbacks
    Dim event As Map
    ' Careful here: we have to use the event name without the 'on' prefix when using AddEventListener
    Request.AddEventListener("load", BANano.CallBack(Me, "OnLoadHTTP", event), True)
    Request.AddEventListener("error", BANano.CallBack(Me, "OnErrorHTTP", event), True)
    
    ' Let's do it!
    Request.RunMethod("send", Null)
End Sub

public Sub OnloadHTTP(event As Map)
    ' Getting our XmlHttpRequest object again
    Dim Request As BANanoObject = event.Get("target")
    
    ' Checking the status
    Dim status As Int = Request.GetField("status").Result
    If status < 200 Or status >= 300 Then
        ' Maybe not allowed? Return an error with ReturnElse
        BANano.ReturnElse("Status code was not 200!")
    Else
        ' All is fine, return a Then
        BANano.ReturnThen(Request.GetField("response").Result)
    End If
End Sub

public Sub OnErrorHTTP(event As Map)
    ' Some other error, return a ReturnElse
    BANano.ReturnElse("Network error")
End Sub

Hope this is OK
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
I see what is happening here. The WebDemo wasn't a good start as I told you. It was a static Website not meant to read user input.

LoadLayoutArray is used here, so your views have post-fixes (e.g. txtUserName_1).

Just use LoadLayout instead for the moment (ignoring the translations). I see if I can rewrite the LoadTexts() method so it works with LoadLayout too tomorrow.
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
No problem - sorted
B4X:
    Select Case CurrentPageName
        Case "home":
            BANano.LoadLayout("#skcontainer1", "Home")
        Case "console":
            BANano.LoadLayout("#skcontainer1", "Console")
        Case "products":
            BANano.LoadLayout("#skcontainer1", "Products")
        Case "links"
            BANano.LoadLayout("#skcontainer1", "Links")
    End Select
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
This should be the replacement for the LoadTexts method when using LoadLayout instead of LoadLayoutArray:

B4X:
public Sub LoadTexts()
    Dim Strings As Map = HTTPRequests.Strings.Get(CurrentPageName)
   
    ' For all the keys in the json map
    For Each key As String In Strings.Keys
        Dim prefix As String = key.SubString2(0,3)
       
        ' We use the prefix to find out what kind of Custom View it is.
        Select Case prefix
            Case "lbl"                               
                Dim lbl As SKLabel = GetViewFromLayout(Me, key)
                If lbl <> BANano.UNDEFINED Then
                    lbl.Text = Strings.Get(key)       
                End If   
            Case "lst"
                Dim lst As SKList = GetViewFromLayout(Me, key)
                If lst <> BANano.UNDEFINED Then
                    lst.Clear
                    Dim itemsStr As String = Strings.Get(key)
                    Dim items() As String = BANano.Split(";", itemsStr)
                    For i = 0 To items.length - 1
                        lst.AppendToList(items(i), Null, False)
                    Next       
                End If   
        End Select
    Next   
End Sub

' a bit of a hack: requires to know that a custom view loaded with LoadLayout is transpiled by BANano as "_" & TheViewNameLowerCased and attached to the class
' The next version of BANano will have a method BANano.GetViewFromLayout(Me, TheViewName) that will do just that.
public Sub GetViewFromLayout(class As Object, id As String) As Object
    ' get this class as a BANanoObject
    Dim MyClass As BANanoObject
    MyClass.Initialize(class)
   
    Return MyClass.GetField("_" & id.ToLowerCase).Result
End Sub

Alwaysbusy
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
Running the above code, I get an error on compile:
B4X:
Parsing code.    Error
Error parsing program.
Error description: Undeclared variable 'httprequests' is used before it was assigned any value.
Error occurred on line: 186 (Main)
    Dim Strings As Map = HTTPRequests.Strings.Get(CurrentPageName)

My code:
B4X:
public Sub LoadTexts()
    Dim Strings As Map = HTTPRequests.Strings.Get(CurrentPageName) <----ERROR HERE
  
    ' For all the keys in the json map
    For Each key As String In Strings.Keys
        Dim prefix As String = key.SubString2(0,3)
      
        ' We use the prefix to find out what kind of Custom View it is.
        Select Case prefix
            Case "lbl"                               
                Dim lbl As SKLabel = GetViewFromLayout(Me, key)
                If lbl <> BANano.UNDEFINED Then
                    lbl.Text = Strings.Get(key)       
                End If   
            Case "lst"
                Dim lst As SKList = GetViewFromLayout(Me, key)
                If lst <> BANano.UNDEFINED Then
                    lst.Clear
                    Dim itemsStr As String = Strings.Get(key)
                    Dim items() As String = BANano.Split(";", itemsStr)
                    For i = 0 To items.length - 1
                        lst.AppendToList(items(i), Null, False)
                    Next       
                End If   
        End Select
    Next       
End Sub
 
Upvote 0
Top