B4J Tutorial [BANanoWebix] Creating a Multi-Page Interface in a SPA

Ola

The latest release of BANanoWebix features a sidebar that when selected, it displays 'different pages' within the same 'index.html file.

LessonMP.gif


At the heart of every BANano based App, there is the '#body' element of a page. Initially this is blank and one needs to feed content to it to create their app. This 'body' element is created automatically by BANano and that is what needs to be generated.

BANano has a BANanoElement class, this works like document.getElementByID(???) or jquerys $('#???') calls, so to get the body element one could....

B4X:
Dim EL As BANanoElement = BANano.GetElement("#body")

This will get the element by id 'body' and enable it to be fed HTML content. To just assume that we were adding a paragraph , one would execute....

B4X:
EL.Append("<p>This is my first paragraph!</p>")
and also add any other HTML they need to make the page alive. This happens in runtime so no other methods should be called to make it work.

Now, assuming that you wanted to show something totally different on the body tag, let's assume an image, you will have to clear the body tag and then overwrite it.

B4X:
'clear the body tag
EL.Empty
'write something else
EL.Append("<img src='image.png' alt='This is an image'/>

This will have the effect of 'deleting' everything that was in the body and now creating the image there.

Thus to create multiple-pages on this SPA framework, one just overwrites the body tag like this over and over again, maybe perhaps a function call or a button click.

The approach followed by webix is similar. Whilst I could replace the complete body tag, we did'nt want to over-write the 'shell' contents of the page i.e. toolbar, sidebar etc, we just wanted to have the middle body of the page replaced.

So we did the following:

1. Created the page and the toolbar and told our lib that we want everything on the page to be rendered on the element with id = body.

B4X:
pg.Initialize("forms", "body").SetTypeSpace("")
    '
    Dim R1 As WixRow
    R1.Initialize("R1")
    'add toolbar
    Dim tblBar As WixToolBar
    tblBar.Initialize("tblBar")
    tblBar.CreateIcon("menuopen").SetIcon("mdi mdi-menu").SetClick(BANano.CallBack(Me, "OpenMenu", Null)).Pop
    tblBar.CreateLabel("heading").SetLabel("BANanoWebix - A Webix Wrapper for BANano").Pop
    tblBar.setPadding(3)
    R1.AddRows(tblBar.Item)

2. We then added the sidebar with its parent and child buttons. This has a click event so that we pick up which id is selected. On each element click, we just render the code module page that is generated to a specific div, in this case, r2c2_content

B4X:
Dim sm As WixSideBar
    sm.Initialize("sm").SetPositionRight("").SetCollapsed(False).SetActiveTitle(True).SetScroll(True)
    '
    sm.AddItem("", "layouts", "L1-L3 Layouts","","mdi mdi-view-dashboard", "","")
    sm.AddItem("layouts", "lesson1", "Lesson 1","","mdi mdi-view-dashboard", "","")
    sm.AddItem("layouts", "lesson2", "Lesson 2","","mdi mdi-view-dashboard", "","")
    sm.AddItem("layouts", "lesson3_1", "Lesson 3.1","","mdi mdi-view-dashboard", "","")
    sm.AddItem("layouts", "lesson3_2", "Lesson 3.2","","mdi mdi-view-dashboard", "","")
    '
    sm.AddItem("", "multiview", "L4 MultiView","","mdi mdi-view-dashboard", "","")
    sm.AddItem("", "toolbar", "L5 ToolBar","","mdi mdi-view-dashboard", "","")
    sm.AddItem("", "dataentry1", "L6 Data Entry","","mdi mdi-view-dashboard", "","")
    sm.AddItem("dataentry1", "dataentry", "L6 Data Entry","","mdi mdi-view-dashboard", "","")
    sm.AddItem("dataentry1", "forms1", "Forms 1","","mdi mdi-view-dashboard", "","")
    sm.AddItem("dataentry1", "forms2", "Forms 2","","mdi mdi-view-dashboard", "","")
    sm.AddItem("", "charts", "L7 Charts","","mdi mdi-view-dashboard", "","")
    '
    sm.AddItem("", "datatable", "L8 DataTable","","mdi mdi-view-dashboard", "","")
    sm.AddItem("datatable", "lesson8_1", "Lesson 8.1","","mdi mdi-view-dashboard", "","")
    sm.AddItem("datatable", "lesson8_2", "Lesson 8.2","","mdi mdi-view-dashboard", "","")
    sm.AddItem("datatable", "lesson8_3", "Lesson 8.3","","mdi mdi-view-dashboard", "","")
    '
    sm.AddItem("", "dataview", "L9 DataView","","mdi mdi-view-dashboard", "","")
    sm.AddItem("", "lists", "L10-L11 Lists","","mdi mdi-view-dashboard", "","")
    sm.AddItem("lists", "list", "L10 List","","mdi mdi-view-dashboard", "","")
    sm.AddItem("lists", "unitlist", "L11 Unit List","","mdi mdi-view-dashboard", "","")
    '
    sm.AddItem("", "property", "L12 Property Sheet", "", "mdi mdi-table", "","")
    '
    sm.AddItem("", "trees", "L13-L14 Trees","","mdi mdi-view-dashboard", "","")
    sm.AddItem("trees", "treeview", "L13 Tree","","mdi mdi-view-dashboard", "","")
    sm.AddItem("trees", "treedata", "L14 Tree Data","","mdi mdi-view-dashboard", "","")
    '
    sm.AddItem("", "menu", "L15 Menu", "", "mdi mdi-table", "","")
    sm.AddItem("", "sidebar", "L16 Side Bar", "", "mdi mdi-table", "","")
    sm.AddItem("", "comments", "L17 Comments", "", "mdi mdi-table", "","")
    sm.AddItem("", "grouplist", "L18 Group List","","mdi mdi-view-dashboard", "","")
    sm.AddItem("", "context", "L19 Contexts", "", "mdi mdi-table", "","")
    sm.AddItem("", "gmap", "L20 GoogleMap", "", "mdi mdi-table", "","")
    sm.AddItem("", "tabbar", "L21 Tab Bar", "", "mdi mdi-table", "","")
    sm.AddItem("", "uploader", "L22 Uploader", "", "mdi mdi-table", "","")
    sm.AddItem("uploader", "lesson22_1", "L22.1 Upload Grid","","mdi mdi-view-dashboard", "","")
    sm.AddItem("uploader", "lesson22_2", "L22.2 Linked List","","mdi mdi-view-dashboard", "","")
    sm.AddItem("uploader", "lesson22_3", "L22.3 Drop Zone","","mdi mdi-view-dashboard", "","")
    '
    sm.AddItem("", "lesson23", "L23 Video","","mdi mdi-view-dashboard", "","")
    sm.AddItem("", "lesson24", "L24 Scroll View","","mdi mdi-view-dashboard", "","")
    sm.AddItem("", "lesson25", "L25 Template","","mdi mdi-view-dashboard", "","")
  
    Dim items As List = sm.Items
    Dim data As List = pg.Unflatten(items,"data")
    sm.SetData(data)

3. We then created a normal HTML div element and placed it as a 'template' inside one of our WixElements. We want that div to fit its parents so we apply some inline styling to set the width and height to 100%.

B4X:
Dim R2C2 As WixElement
    R2C2.Initialize("R2C2")
    Dim div As UOENowHTML
    div.Initialize("r2c2_content","div").SetStyle("width","100%").SetStyle("height","100%")
    R2C2.SetTemplate(div.HTML)
    '
    R2.AddColumns(R2C2.item)

The name of this div is r2c2_content. So each time an item in the sidebar is clicked, we want it to be rendered on this container div.

4. After the page is rendered, we add an item click to the side menu so that we can trap each item that is clicked.

B4X:
pg.ui
    '
    Dim meid As Map
    pg.OnItemClick("sm", BANano.CallBack(Me, "itemClick", Array(meid)))

Now each time that happens, the code module or rather 'page' is generated in its entirety and rendered to r2c2_content due to the fact that each WixElement has a container attribute that you can indicate as to tell it which div to render the contents of that object based element to. This is done by the .SetContainer(???) call on the page.

B4X:
Sub itemClick(meID As String)
    Select Case meID
    Case "lesson8_3"
        pgLesson8_3.Init("r2c2_content")     
    Case "lesson24"
        pgScrollView.Init("r2c2_content")
    Case "lesson25"
        pgTemplate.Init("r2c2_content")
    Case "forms1"
        pgForms.Init("r2c2_content")
    Case "forms2"     
        pgForms1.Init("r2c2_content")
    Case "lesson23"
        pgVideo.Init("r2c2_content")
    Case "lesson22_1"
        pgUploader1.Init("r2c2_content")
    Case "lesson22_2"
        pgUploader2.Init("r2c2_content")
    Case "lesson22_3"
        pgUploader3.Init("r2c2_content")
    Case "tabbar"
        pgTabBar.Init("r2c2_content")
    Case "gmap"
        pgGoogleMap.Init("r2c2_content")
    Case "context"
        pgContext.Init("r2c2_content")
    Case "comments"
            pgComments.Init("r2c2_content")
    Case "sidebar"
        pgSideBar.Init("r2c2_content")
    Case "menu"
        pgMenu.Init("r2c2_content")
    Case "treeview"
        pgTree.Init("r2c2_content")
    Case "treedata"
        pgTreeTable.Init("r2c2_content")
    Case "property"
        pgPropertySheet.Init("r2c2_content")
    Case "grouplist"
        pgGroupList.Init("r2c2_content")
    Case "unitlist"
        pgUnitList.Init("r2c2_content")
    Case "list"
        pgList.Init("r2c2_content")
    Case "dataview"
        pgDataView.Init("r2c2_content")
    Case "lesson8_1"
        pgDataTable.Init("r2c2_content")
    Case "lesson8_2"
        pgDataTable1.Init("r2c2_content")
    Case "charts"
        pgCharts.Init("r2c2_content")
    Case "lesson1"
        pgLayout.Init("r2c2_content")
    Case "lesson2"
        pgLayouts.Init("r2c2_content")
    Case "lesson3_1"
        pgLayouts1.init("r2c2_content")
    Case "lesson3_2"
        pgLayouts2.init("r2c2_content")
    Case "multiview"
        pgMultiView.Init("r2c2_content")
    Case "toolbar"
        pgToolBar.Init("r2c2_content")
    Case "dataentry"
        pgDataEntry.Init("r2c2_content")     
    End Select
End Sub

The Page Initialization

B4X:
'initialize the page and empty the page '#body' element
Public Sub Initialize(pgID As String, pgContainer As String) As WixPage
    hints.Initialize
    Dollar.Initialize("$$")
    ID = pgID.tolowercase
    webix.Initialize("webix")
    Page.Initialize(ID)
    'init other stuff
    EnumButtonTypes.Initialize
    EnumLayoutTypes.Initialize
    EnumWixIcons.Initialize
    SetContainer(pgContainer)
    Return Me
End Sub

As noted above, this calls SetContainer, which calls the .Empty BANanoElement method and then set the container property of the Page (WixElement).

B4X:
'set the container of the page
Sub SetContainer(contID As String) As WixPage
    contID = contID.tolowercase
    Dim sKey As String = "#" & contID
    Page.Container = contID
    BANano.GetElement(sKey).empty
    Return Me
End Sub

All of this in effect, clearing the div contents and then overwriting them each time a page is created, creating an 'illusion' that we have multiple-pages in our SPA.

Ta
 
Last edited:
Top