B4J Tutorial [BANanoWebix] Creating Multi-Page Apps - Part 4

Mashiane

Expert
Licensed User
Ola

Download BANanoWebix Things

The project source code is on the BANanoWebixMultiPage folder. Ensure to update the external libraries folder for b4j with contents of the 1. Libraries folder.

Part 3 of our lesson looked at the addition of the grid and forms for both cities and positions of our app. In Part 4, we will look at adding more functionality to our app.

1. For grids, detect 'delete' and 'insert' key press and perform relevant functions.
2. For deletes, show a confirm dialog and process a delete once Yes is selected. This removes the record from the db and refreshes the data-table.
3. Hiding & Showing elements of the page depending on what is being actioned.
4. CRUD functionality for both 'add' and 'edit' modes.
5. Data-table double click to activate 'edit' mode.
6. Adding toolbar to a form - to house crud related buttons
7. Using spacers to make our forms proper for displays.


We want when the cities / positions pages are selected on the side bar, the relevant selected page should show, the existing records for either should show and the form for CRUD functionality should be shown.

As we are continuing from Part 3, we have just added more functions to ensure that both screens work as expected.

B4X:
'controller code for the side menu
Sub SettingsHandler(pg As WixPage, menuitem As String)
    ourclients.OpenWait("ourclients", "ourclients")
    Page = pg
    Select Case menuitem
        Case "settings_positions"
            pg.Show("mv_settings_positions")
            modPositions.SetPage(Page)
            modPositions.LoadPositions
            Page.Clear("formpositions")
            Page.ClearValidation("formpositions")
            Page.Show("btnnewposition")
            Page.HideMulti(Array("btncancelposition","btnsaveposition","btndeleteposition"))
        Case "settings_cities"
            pg.Show("mv_settings_cities")
            modCities.SetPage(Page)
            modCities.LoadCities
            Page.Clear("formcities")
            Page.ClearValidation("formcities")
            Page.Show("btnnewcity")
            Page.HideMulti(Array("btncancelcity","btnsavecity","btndeletecity"))
    End Select
End Sub
Positions / Cities

When this page is selected, we link the Page objects with .SetPage(?), on the respective modules this stores a global variable called Page and opens the BANanoSQL database.

After that the existing records are loaded with LoadPositions / LoadCities

We want to ensure that the details of the forms are cleared and only the needed buttons are shown, case in point 'bntNew...'

These buttons are sitting in the toolbars at the bottom of the page. To separate the form and the toolbar at the bottom we used a 'spacer'

All the code that is related to maintaining Cities in happening in the modCities module and all the code to manage the positions is happening in the modPositions modules. It is better this way as managing and maintaining the code is easier.

In Part 3, we only added form elements to our forms and did not include the toolbar, so in the CreateForm?? method, we first start by adding a spacer and then the toolbar with the needed icons.

B4X:
form.AddRowsSpacer("")
    '
    Dim toolbar1 As WixToolBar
    toolbar1.Initialize("tlbpos")
   
    Dim btnBack As WixIcon
    btnBack.Initialize("btnback")
    btnBack.SetIcon("mdi mdi-keyboard-backspace")
    btnBack.SetTooltip("Go back")
    btnBack.SetWidth("100")
    btnBack.SetClick(BANano.CallBack(Me,"btnback_click",Null))
    toolbar1.AddIcon(btnBack)
   
    toolbar1.AddSpacer
       
    Dim btnnewposition As WixIcon
    btnnewposition.Initialize("btnnewposition")
    btnnewposition.SetIcon("mdi mdi-plus")
    btnnewposition.SetTooltip("Add a new position")
    btnnewposition.SetWidth("100")
    btnnewposition.SetClick(BANano.CallBack(Me,"btnnewposition_click",Null))
    toolbar1.AddIcon(btnnewposition)

    Dim btncancelposition As WixIcon
    btncancelposition.Initialize("btncancelposition")
    btncancelposition.SetIcon("mdi mdi-cancel")
    btncancelposition.SetTooltip("Cancel new position")
    btncancelposition.SetWidth("100")
    btncancelposition.SetClick(BANano.CallBack(Me,"btncancelposition_click",Null))
    btncancelposition.SetHidden(True)
    toolbar1.AddIcon(btncancelposition)
   

    Dim btnsaveposition As WixIcon
    btnsaveposition.Initialize("btnsaveposition")
    btnsaveposition.SetIcon("mdi mdi-content-save")
    btnsaveposition.SetTooltip("Save the position")
    btnsaveposition.SetWidth("100")
    btnsaveposition.SetClick(BANano.CallBack(Me,"btnsaveposition_click",Null))
    btnsaveposition.SetHidden(True)
    toolbar1.AddIcon(btnsaveposition)

    Dim btndeleteposition As WixIcon
    btndeleteposition.Initialize("btndeleteposition")
    btndeleteposition.SetIcon("mdi mdi-trash-can")
    btndeleteposition.SetTooltip("Delete position")
    btndeleteposition.SetWidth("100")
    btndeleteposition.SetClick(BANano.CallBack(Me,"btndeleteposition_click",Null))
    btndeleteposition.SetHidden(True)
    toolbar1.AddIcon(btndeleteposition)

    form.AddRows(toolbar1.Item)

As noted above, some of these icons are hidden. To ensure that they are not very close to each other we set the width of each button to be 100. We also assign events to them for adding, cancelling, saving, deleting etc.

We also added required on the form elements and added some validation because the contents are compulsory.

For example...

B4X:
value.SetRequired(True)
    value.SetValidateIsNotEmpty(True)
    value.SetInvalidMessage("The position should be specified")
 
Last edited:

Mashiane

Expert
Licensed User
Detecting Double Click / KeyPress on the Data-Table

As we want to detect a double click on the data-table and also a keypress e.g. the delete / insert keys, we attach events to the data-table before we conclude its creation.

B4X:
'add events to the dtpositions
    Dim arguements As Object
    dtpositions.DataTable.OnItemDblClick(BANano.CallBack(Me,"dtpositions_dblclick",Array(arguements)))
    dtpositions.DataTable.OnKeyPress(BANano.CallBack(Me,"dtpositions_keypress",Array(arguements)))
So when an entry in the data-table is double-clicked (we have set row selection), the edit mode is activated and the form is updated with the contents of the selected grid item.

B4X:
Sub dtpositions_dblclick(arguements As Object)
    ' turn edit on
    Dim item As Map = Page.GetSelectedItem("dtpositions",False)
    If item <> Null Then
        Page.SetValues("formpositions", item)
        Mode = "E"
        Page.HideMulti(Array("btnnewposition"))
        Page.ShowMulti(Array("btncancelposition","btnsaveposition","btndeleteposition"))
        Page.Focus("positions.id")
    End If
End Sub
The form is linked to the grid using the 'name' property of the input elements. On edit we hide the new icon and show cancel, save and delete.

When a key is pressed, for example, the insert key, the 'addition' mode is activated, this prepares the form for entry. On the other hand when the delete keyboard key is pressed, a confirmation is provided to ask the user if they want to delete the record.

B4X:
Sub dtpositions_keypress(arguements As Object)
    Dim kCode As Int = BANano.parseInt(arguements)
    Select Case kCode
        Case 45
            'insert
            btnnewposition_click
        Case 46
            'delete
            Dim confirmresult As Boolean = False
            Dim cb As BANanoObject = BANano.CallBack(Me,"dtpositions_delete",Array(confirmresult))
            Page.Confirm(cb, "Confirm Delete", "Are you Sure Want to delete the selected position? You will not be able to undo your changes. Continue?")
    End Select
End Sub

Sub dtpositions_delete(confirmresult As Boolean)
    If confirmresult = False Then Return
    Dim item As Map = Page.GetSelectedItem("dtpositions",False)
    If item = Null Then Return
    Dim did As String = item.Get("id")
    '
    Dim alasql As BANanoAlaSQL
    alasql.Initialize
    Dim rs As AlaSQLResultSet = alasql.DeleteWhere("positions", CreateMap("id":did))
    rs.Result = ourclients.ExecuteWait(rs.query, rs.args)
    Page.clear("formpositions")
    Page.ClearValidation("formpositions")
    Page.Show("btnnewposition")
    Page.HideMulti(Array("btncancelposition", "btnsaveposition", "btndeleteposition"))
    LoadPositions
End Sub
On confirmation, the selected record is read from the data-table, the 'id' value is read, the record is deleted from the underlying database table and the grid listing refreshed.

If on the other hand the 'insert' key is pressed, the 'addition' of a new record is activated. The 'max' of the 'id' column is read, this is incremented by 1 and the form is updated for data entry.

B4X:
Sub btnnewposition_click
    Page.Hide("btnnewposition")
    Page.Show("btncancelposition")
    Page.Show("btnsaveposition")
    Page.Hide("btndeleteposition")
    
    'set the mode
    Mode = "A"
    'clear the form
    Page.Clear("formpositions")
    Page.ClearValidation("formpositions")
    'set the focus to element
    Page.Focus("positions.id")
    'get next available id
    'initialize the helper class
    Dim alaSQL As BANanoAlaSQL
    alaSQL.Initialize
    'generate the create table sql
    Dim rs As AlaSQLResultSet = alaSQL.GetMax("positions", "id")
    'execute the create table command
    rs.Result = ourclients.ExecuteWait(rs.query, rs.args)
    Dim lastID As Int
    If rs.result.Size = 0 Then
        lastID = 0
    Else
        'get the record
        Dim rec As Map = rs.result.get(0)
        Dim lID As String = rec.GetDefault("id","0")
        lastID = BANano.parseint(lID)
    End If
    lastID = lastID + 1
    Page.SetValue("positions.id", lastID)
End Sub
Whilst the 'id' input element is shown here for brevity, in real world situations, to avoid manual editing, this can be hidden / rather disabled.
 

Mashiane

Expert
Licensed User
Saving Records

Depending on the mode being active, whether 'A' for addition or 'E' for editing, saving the record will perform an insert on 'A' and an update when 'E'

B4X:
Sub btnsaveposition_click
    'validate the form
    Dim bValidate As Boolean = Page.Validate("formpositions")
    If bValidate = False Then
        Page.Message_Error("There are some missing contents for this record, please rectify!")
        Return
    End If
    
    Select Case Mode
        Case "A"
            'adding a new position
            Dim rec As Map = Page.GetValues("formpositions")
            Dim alaSQL As BANanoAlaSQL
            alaSQL.Initialize
            Dim rs As AlaSQLResultSet = alaSQL.Insert("positions", rec)
            rs.Result = ourclients.ExecuteWait(rs.query, rs.args)
        Case "E"
            'updating an existing position
            Dim rec As Map = Page.GetValues("formpositions")
            Dim eid As String = rec.Get("id")
            Dim alaSQL As BANanoAlaSQL
            alaSQL.Initialize
            Dim rs As AlaSQLResultSet = alaSQL.UpdateWhere("positions", rec, CreateMap("id":eid))
            rs.Result = ourclients.ExecuteWait(rs.query, rs.args)
    End Select
    Mode = ""
    Page.clear("formpositions")
    Page.ClearValidation("formpositions")
    Page.Show("btnnewposition")
    Page.Hide("btncancelposition")
    Page.Hide("btnsaveposition")
    Page.Hide("btndeleteposition")
    LoadPositions
End Sub
The form contents are validated. If they are valid, depending on the mode, an insert takes place or an update takes place.

Where duplicates should be avoided, a next step after the validation can be undertaken to check if duplicates will not be created on inserts of new records.

Part 5 of this will delve on the clients screen and how the positions and the cities data can be used to load selects/combo boxes.

Ta!
 
Top