B4J Tutorial [ABMaterial] One Page, Many Uses

TripInspect.png


This example uses one ABM page to handle all tables listed under "Configure App".
In an effort to reduce code size (and maintenance), number of pages and duplicate methods, I am creating an internal ABM framework (strategy) to reuse the same page for like purposes. So far, so good.

Each sub_item of Configure Apps ( Company, Users, Terminals, HOS Rules, etc ) uses the same page, theme and (essentially) the same grid layout. The only thing that changes is the SQL query to retrieve the row items and the row headers to state each column title.

As alwaysbusy stated earlier, it is important to configure the grid upfront - knowing how you want to present your data - now and in the future. But, how do we know what is the future (your customer demands this...)? Simple: Add other BLANK rows... (with 1, 2, 3 or rows and more columns...) If empty (not used), they don't affect your layout (consume padded space above or below). This way, you can use them when you need too.

This picture shows an additional row (on top) that is ONLY used (made visible) when required. It is a toolbar with 3 buttons that refreshes the table based on the selected button_click (Trucks, Trailer, Other).

For those who are new to ABM, don't fret... I am green as well. You just need someone to guide you through the initial learning phase. Hopefully I, and others experts will contribute examples to help you on your way. My knowledge has been garnered from what alwaysbusy provided in the demo, and experimenting from there.

This post will be updated with specifics of how to get to this point (with code examples) - since now it is all just suggestive. Next, I shall introduce the basic and Modal Forms for each table hopefully using the same (page) strategy... Wish me luck.

What is truly amazing is that everything was written in ABM using B4J! Not one line of code written in HTML(5), JavaScript or php!!! How can you beat that? !!!

Thanks
 
Last edited:

Harris

Expert
Licensed User
Longtime User
Table Headers and getting data...


B4X:
public Sub BuildPage()
    ' initialize the theme
    BuildTheme

    ' initialize this page using our theme
    page.InitializeWithTheme(Name,   "/ws/" & AppName & "/" & Name,  False,  theme)
    page.ShowLoader=True
    page.NeedsChips = True

    ABMShared.BuildNavigationBar(page, ABMShared.pgActionName  , "../images/logo.png",  "",  "Config",   ABMShared.pgActionName)
    ' create the page grid
    page.AddRowsM( 1,True,  15,  0, "rowtheme").AddCellsOSMP(1,0,0,0,4,4,4,5,5,30,10,"").AddCellsOSMP(1,0,0,0,4,4,4,5,5,30,10,"").AddCellsOSMP(1,0,0,0,4,4,4,5,5,30,10,"")
    page.AddRowsM( 1,True,  0,  5, "").AddCells12( 1,"")    ' spare row
    page.AddRowsM( 1,True, 20,  5, "").AddCells12( 1,"")

    page.BuildGrid 'IMPORTANT once you loaded the complete grid AND before you start adding components


    Dim btntruck As ABMButton
    btntruck.InitializeFlat( page , "btntruck", "mdi-maps-local-shipping", "LEFT", "Trucks","bigblue")
    page.Cell(1,1).AddComponent(btntruck)
    page.Row(1).Visibility = ABM.VISIBILITY_HIDE_ALL

    Dim btntrailer As ABMButton
    btntrailer.InitializeFlat( page , "btntrailer", "mdi-editor-format-strikethrough", "LEFT", "Trailers","bigblue")
    page.Cell(1,2).AddComponent(btntrailer)
    page.Row(1).Visibility = ABM.VISIBILITY_HIDE_ALL

    Dim btnother As ABMButton
    btnother.InitializeFlat( page , "btnother", "mdi-maps-directions-car", "LEFT", "Other","bigblue")
    page.Cell(1,3).AddComponent(btnother)
    page.Row(1).Visibility = ABM.VISIBILITY_HIDE_ALL

    If ABMShared.pgActionName = "Vehicles" Or ABMShared.pgActionName = "Inspections" Then
       page.Row(1).Visibility = ABM.VISIBILITY_ALL
    End If

    ' add a modal sheet template to enter user information
    page.AddModalSheetTemplate(BuildInputSheet)
    ' add a modal sheet template for a yes no msgbox
    page.AddModalSheetTemplate(BuildMsgBoxYesNo)
    ' add a modal sheet template for a  msgbox
    page.AddModalSheetTemplate(BuildMsgBox)
    ' add a modal sheet template for an upload
    page.AddModalSheetTemplate(BuildAttachmentSheet)
    ' add a modal sheet template to enter case information
    page.AddModalSheetTemplate(BuildNoteInputSheet)


    ' create a table
    Dim tblCases As ABMTable
    Select Case ABMShared.pgActionName

        Case  "Company"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String( "ID"  ,"User Name", "Owner Name" , "City" , "Pass Code","View / Edit" ,"Delete"   ))
        tblCases.SetHeaderThemes(    Array As String(  "bgc" , "bgc"    , "bgc"      , "bgc"  , "bgc"  , "bgc"        ,"bgc"    ))

        Case  "Users"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String( "ID"  ,"User Name", "Login Name" , "Type" , "Active","View / Edit" ,"Delete"   ))
        tblCases.SetHeaderThemes(    Array As String(  "bgc" , "bgc"    , "bgc"      , "bgc"  , "bgc"  , "bgc"        ,"bgc"    ))

        Case  "Terminals"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String( "ID"  ,"Terminal Name", "Address" , "City" , "State/Prov","View / Edit" ,"Delete"   ))
        tblCases.SetHeaderThemes(    Array As String(  "bgc" , "bgc"    , "bgc"      , "bgc"  , "bgc"  , "bgc"        ,"bgc"    ))


        Case  "Inspections"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String( "ID"  ,"Vehicle Name", "Unit Type" , "Image", "View / Edit" ,"Delete"   ))
        tblCases.SetHeaderThemes(    Array As String(  "bgc" , "bgc"    , "bgc"      , "bgc"  , "bgc"        ,"bgc"    ))

        Case  "HOS"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String( "ID"  ,"Rule Name", "Description" , "Selected", "View / Edit" ,"Delete"   ))
        tblCases.SetHeaderThemes(    Array As String(  "bgc" , "bgc"    , "bgc"      , "bgc"  , "bgc"        ,"bgc"    ))

        Case  "Employees"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String("ID"  ,"Number", "First Name" , "Last Name" , "Type","View / Edit" ,"Delete"))
        tblCases.SetHeaderThemes(     Array As String("bgc" , "bgc"   , "bgc"         , "bgc"        , "bgc"  , "bgc"       ,"bgc"    ))

        Case  "Vehicles"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String( "ID"  ,"Vehicle Number", "VIN" , "Notes" , "Type","View / Edit" ,"Delete"   ))
        tblCases.SetHeaderThemes(    Array As String(  "bgc" , "bgc"           , "bgc"  , "bgc"    , "bgc"  , "bgc"        ,"bgc"    ))

        Case  "Devices"
        tblCases.Initialize(page, "tblCases",   False,  True, True, "tbltheme")
        tblCases.SetHeaders(         Array As String( "ID"  ,"User Name", "Serial #" , "Make" , "Model","View / Edit" ,"Delete"   ))
        tblCases.SetHeaderThemes(    Array As String(  "bgc" , "bgc"    , "bgc"      , "bgc"  , "bgc"  , "bgc"        ,"bgc"    ))


    End Select

    tblCases.SetFooter("Total number of records: 0", 12,"bg")

    page.Cell(3,1).AddComponent(tblCases)

    BuildFooterFixed

End Sub

The important bit:
Select Case ABMShared.pgActionName

It comes from:
page.NavigationBar.AddSideBarSubItem("Config", "Company", "Company", "mdi-action-home", "../Employees") ' where "Company" is the action in Page_NavigationbarClicked



B4X:
Sub Page_NavigationbarClicked(Action As String, Value As String)
    page.SaveNavigationBarPosition
    If Action = "Cases" Then Return

    If Action = "LogOff" Then
        ABMShared.LogOff(page, AppName)
        Return
    End If

    ABMShared.pgActionName = Action ' set the string so Case will work

    ABMShared.NavigateToPage(ws, Value)
Log(" Set Action: "& Action)

End Sub

Get data....
B4X:
private Sub LoadCases(fromPage As Int) 
    Dim tblCases As ABMTable = page.Component("tblCases") 
 
    Dim SQL As SQL = DBM.GetSQL
    Dim SQL_str, SQL_Str2 As String

    Log(" Current Page: "&ABMShared.pgActionName)

    Select Case ABMShared.pgActionName

      Case "Company"
        SQL_str = "SELECT Count(id) as IDS FROM members WHERE id = "&Main.comp_id
        SQL_Str2 =    "SELECT id, username, owner_name, city, deviceid FROM members WHERE id = "&Main.comp_id&"  "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs

      Case "Users"
        SQL_str = "SELECT Count(UserID) as IDS FROM users WHERE comp_id = "&Main.comp_id
        SQL_Str2 =    "SELECT UserID, UserName, UserLogin, UserType, UserActive FROM users WHERE comp_id = "&Main.comp_id&" ORDER BY UserName "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs

      Case "Terminals"  
        SQL_str = "SELECT Count(PK) as IDS FROM terminal WHERE comp_id = "&Main.comp_id
        SQL_Str2 =    "SELECT PK, name, address1, city, st_prov FROM terminal WHERE comp_id = "&Main.comp_id&" ORDER BY name "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs

      Case "HOS"  
        SQL_str = "SELECT Count(PK) as IDS FROM hos_rules"
        SQL_Str2 =    "SELECT PK, rule_name, rule_description, rule_selected FROM hos_rules ORDER BY rule_name "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs


      Case "Inspections"  
        SQL_str = "SELECT Count(PK) as IDS FROM insptype_mast WHERE comp_id =  0 AND Trk_Trl = "&veh_type '&Main.comp_id
        SQL_Str2 =    "SELECT l1.PK, l1.Name, l2.utype, l1.TSpare1 FROM insptype_mast l1, unittype l2 WHERE l1.Trk_Trl = l2.PK AND l1.Trk_Trl = "&veh_type&" AND comp_id = 0 ORDER BY Name "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs


      Case "Employees"  
        SQL_str = "SELECT Count(PK) as IDS FROM emp WHERE comp_id = "&Main.comp_id
        SQL_Str2 =    "SELECT PK, Employee_no, First_name, Last_Name, Pin FROM emp WHERE comp_id = "&Main.comp_id&" ORDER BY Last_name "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs
       
      Case "Vehicles"
        SQL_str = "SELECT Count(PK) as IDS FROM vehicle WHERE comp_id = "&Main.comp_id&" AND unit_type = "&veh_type
        SQL_Str2 =    "SELECT l1.PK, l1.unit_number, l1.vin, l1.notes, l2.utype FROM vehicle l1, unittype l2 WHERE l1.unit_type = l2.PK AND l1.unit_type = "&veh_type&" AND comp_id = "&Main.comp_id&" ORDER BY unit_number "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs
       
      Case "Devices"
        SQL_str = "SELECT Count(PK) as IDS FROM devices WHERE comp_id = "&Main.comp_id
        SQL_Str2 =    "SELECT PK, username, serial, make, model FROM devices WHERE comp_id = "&Main.comp_id&" ORDER BY username "&" LIMIT "& ((fromPage - 1) * iRecs) & ", "&iRecs
     
    End Select

    Dim numcases As Int = DBM.SQLSelectSingleResult(SQL, SQL_str)
    Dim cases As List = DBM.SQLSelect(SQL, SQL_Str2)
    If cases.Size = 0 And fromPage > 1 Then
        ' we are on a page without any lines (maybe removed by other user?)
        DBM.CloseSQL(SQL)
        fromPage = fromPage - 1
        LoadCases(fromPage)
        Return
    End If

    tblCases.SetFooter("Total number of records: " & numcases, 12,"bg")
    tblCases.Clear

    For i = 0 To cases.Size - 1
        Dim tblFields As Map = cases.Get(i)

        Dim rCellValues As List
        Dim rCellThemes As List
        rCellValues.Initialize
        rCellThemes.Initialize
     
        For j = 0 To tblFields.Size - 1 
            Dim var As String
            var =     tblFields.GetValueAt(j) ' init as string to avoid null_pointer error (when return is null)
         
            If ABMShared.pgActionName = "Inspections" Then   ' we shall check to see if this is an image to load (stores image name in table... ie. class8.jpg)
               If tblFields.GetKeyAt(j) = "tspare1" Then
                  Log("image to get: "&var)
                  Dim img As ABMImage
                  img.Initialize(page , "img"&j&i ,"../images/pics/"&var, 1.0)
                  img.SetFixedSize( 120,75)
                  rCellValues.Add(img)
                  rCellThemes.Add("nocolor")
               Else
                  rCellValues.Add(var)
                  rCellThemes.Add("nocolor")
               End If  
            Else
                rCellValues.Add(var)
                rCellThemes.Add("nocolor")
            End If
        Next     
     
     
        Dim btnEdit As ABMButton
        btnEdit.InitializeFloating(page, "btnEdit", "mdi-action-visibility", "")
        rCellValues.Add(btnEdit)
        rCellThemes.Add("nocolor") 
     
        If UserType = "1" Then 
            Dim btnDelete As ABMButton
            btnDelete.InitializeFloating(page, "btnDelete", "mdi-action-delete", "")
            rCellValues.Add(btnDelete)
            rCellThemes.Add("nocolor")     
        End If
     
        tblCases.AddRow(  "uid" & i, rCellValues)
        tblCases.SetRowThemes(rCellThemes) ' make sure you have as many items in rCellThemes as in rCellValues!  Must follow IMMEDIATELY AFTER AddRow!
    Next
    tblCases.Refresh
 
    DBM.CloseSQL(SQL)
 
    If (numcases mod iRecs > 0) Or (numcases = 0) Then
        numcases = numcases/iRecs + 1
    Else
        numcases = numcases/iRecs
    End If
    pagination.SetTotalNumberOfPages(numcases)
    pagination.SetActivePage(fromPage)
    pagination.Refresh
 
End Sub
 
Last edited:

Harris

Expert
Licensed User
Longtime User
You shouldn't build queries with string concatenation. Especially not on server solutions (SQL injection).

Use parameterised queries. Simpler and safer.

However I agree (best practice), I looked through the generated index.html and did not find where these query strings were being created or exposed for injection?

I thought (right or wrong) that server side creation of queries was safe from injection... as in RDC (resides on server and does use parameterised queries however) ?

Without a long explanation (and consuming your limited time), I shall take your advice and proceed as recommended. I generally do, just being lazy in this case. DBUtils handles this quite well.

This type of feedback is most helpful in correcting the errors of our ways!

Thanks
 
Last edited:
Top