B4J Tutorial [BANanoVueMaterial] Exploring Components & Routers Basics

Ola

BVMComponentsRouters.gif


The current methodology of adding pages to the BVM app is throught .AddPage method and we are using the v-show directive to show and hide pages.

So I decided to start on the basics of components and routers. In terms of the VueJS documentation, a component is a Vue instance that cane have its own methods, own data bindings etc,

In this example we create 2 components and 2 routers. To display the router page we use a router view component. In one component we detect a mouse enter and mouse leave event and link that own methods for that component. To define each component, we use a B4J code module.

Both the router page and component are based on the VMComponent class we have created.

Note that with this we have indicated a history mode meaning that we can go back and forth based on the internet explorer navigation.
 

Mashiane

Expert
Licensed User
Longtime User
Detecting Mouse Events.. Creating the component

1. We create a div with some H1 which is linked to a {{ name }} state.
2. We set the initial value of the name to Mashy.
3. We then assign an event for each mouse event, eg. this changes the name between Ben and Mashy.
4. The component name is comp1 i.e. the tag of the html element we are creating

B4X:
'Static code module
Sub Process_Globals
    Private comp1 As VMComponent
    Private vue As BANanoVue
    Private vm As BANanoVM
End Sub

Sub Import
    vm = pgIndex.vm
    vue = vm.vue
    comp1.Initialize(vue, "comp1", "",  Me)
   
    'create a div to house the template
    Dim div As VMElement = vue.CreateDiv("")
    'create an h1 with a data element
    Dim h1 As VMElement = vue.CreateH1("")
    h1.SetText("This is coming from the component 1, create by {{ name }}!")
    'add a mouseover event
    h1.SetEvent("@mouseover",  "changename")
    h1.SetEvent("@mouseout",  "original")
    'add h1 to template
    div.AddComponent(h1.tostring)
    'set the overall template
    comp1.SetTemplate(div.tostring)
    'set the state of the element we are using, this will be reactive
    comp1.SetData("name", "Mashy")
    'add to methods
    comp1.SetMethod(Me, "original")
    'add to methods
    comp1.SetMethod(Me, "changename")
       
    'add component to vue
    vue.AddComponent(comp1)
End Sub

Sub changename
    comp1.SetData("name", "Ben")
End Sub

Sub original
    comp1.setdata("name", "Mashy")
End Sub

Adding our own component to the main page

Now that we have created our component named comp1, we need to add it to the master page. Lets add this on pgIndex.

B4X:
'*copy code here to add to thos page
    'create a div to hold the component
    Dim div As VMElement = vue.CreateDiv("")
    'create the component
    Dim c1 As VMElement = vue.CreateOwnComponent("c1", "comp1")
    'add component to parent
    div.AddComponent(c1.tostring)
    '
    Dim c2 As VMElement = vue.CreateOwnComponent("c2", "comp2")
    'add component to parent
    div.AddComponent(c2.tostring)

So everthing created within the comp1 component will be displayed within the c1 element here.

We also ensure that the component is registered for use by the VueJS app.

B4X:
'add component to vue
    vue.AddComponent(comp1)
'
 

Mashiane

Expert
Licensed User
Longtime User
Creating the Dynamic Component (Red Text)

We also attempt to create a dynamic component, these use a v-bind:is directive

B4X:
'Static code module
Sub Process_Globals
    Private dyna As VMComponent
    Private vue As BANanoVue
    Private vm As BANanoVM
End Sub

Sub Import
    vm = pgIndex.vm
    vue = vm.vue
    dyna.Initialize(vue, "dyna", "", Me)
    Dim div As VMElement = vue.CreateDiv("")
    Dim span As VMElement = vue.CreateSpan("")
    span.SetStyleSingle("font-size", "25px")
    span.SetStyleSingle("color", "red")
    span.SetText("Dynamic Component")
    div.AddComponent(span.tostring)
    dyna.AddComponent(div.tostring)
    vue.AddComponent(dyna)
End Sub

We also register this and add it to the main page.
 

Mashiane

Expert
Licensed User
Longtime User
Router Link 1 (Page 1) and Router Link 2 (Page 2)

We want to show different pages on the main page, also ensuring that the location URL is also updated. In come the routers.

Let's add router links (anchors) and a router view (to view the pages) to the main page.

B4X:
'create router links
    Dim p As VMElement = vue.CreateP("")
    Dim lnk1 As VMElement = vm.CreateRouterLink("", modR1.r1.path, "Router Link 1")
    p.AddComponent(lnk1.tostring)
    Dim lnk2 As VMElement = vm.CreateRouterLink("", modR2.r2.path, "Router Link 2")
    p.AddComponent(lnk2.tostring)
   
    div.AddComponent(p.ToString)
    'add route links
    Dim rv As VMElement = vm.CreateRouterView("")
    div.AddComponent(rv.tostring)

The router-view will be used to show the different pages. So as soon as the links are clicked, these show the contents of the page inside the router-view.

To create the "pages", we use the same VMComponent class we did before. As you have noted, when we click each link , we see a coloured div.

Let's create the first "page"

B4X:
'Static code module
Sub Process_Globals
    Public r1 As VMComponent
    Private vue As BANanoVue
    Private vm As BANanoVM
End Sub

B4X:
Sub AddRouter
    vm = pgIndex.vm
    vue = vm.vue
    r1.Initialize(vue, "r1", $"/${Main.appname}/r1"$, Me)
   
    'create a div to house the template
    Dim div As VMElement = vue.CreateDiv("")
    div.SetStyleSingle("border-radius", "20px")
    div.SetStyleSingle("background-color", "cyan")
    div.SetStyleSingle("width", "200px")
    div.SetStyleSingle("height", "50px")
    div.SetStyleSingle("margin", "10px")
    div.SetStyleSingle("font-size", "25px")
    div.SetStyleSingle("padding", "10px")
    div.SetText("This is router 1")
    r1.SetTemplate(div.tostring)
    vue.AddRoute(r1)
End Sub

Note that unlike before, there are some important things to note here.

1. The path of this page as defined here.

B4X:
r1.Initialize(vue, "r1", $"/${Main.appname}/r1"$, Me)

and how we now add the router to Vue using..

B4X:
vue.AddRoute(r1)

We use the same methodology for the 2nd "page" by creating the whole she-bang and then injecting it to vue.
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Exploring Computed Properties, Filters and Watchers

1. Computed Properties


On the main page, we added a few things to demonstrate this..

B4X:
vue.setdata("firstname", "Anele")
    vue.SetData("lastname", "Mbanga")
    '
    Dim fname As VMElement = vue.CreateH1("").SetText("The fullname is {{ getfullname }}")

We want the {{ getfullname }} property to be "computed" by concatinating the first name and last name.

1. We then tell the vue instance, that we have a computed property. This has a call back method.

B4X:
vue.SetComputed("getfullname", Me, "getfullname1")

This gets the saved state values and binds them together and returns the result.

B4X:
Sub getfullname1 As String
    Dim fname As String = vue.getdata("firstname")
    Dim lname As String = vue.GetData("lastname")
    Return $"${fname} ${lname}"$
End Sub

Each time a new state is fed for "firstname" or "lastname" with vue.SetData(?, ?) then "getfullname" property will change with the result of the callback.

2. Filters

These act like computed properties but are useful for formatting output.

We want to show the total length of the "getfullname" result. We define a filter like element.

B4X:
Dim fnamecount As VMElement = vue.CreateH1("").SetText("The count of strings is {{ getfullname | countletters }}")

We define that we get the details from a filter callback.

B4X:
vue.SetFilter("countletters", Me, "countletters1")

This takes the obtained value and then executes what is needed. In this case it will return 12 as depicted.

B4X:
Sub countletters1(value As String) As Int
    Return value.length
End Sub

3. Watchers

You can watch changes in states and then executing callbacks when these state propeties change. For this we have added some input boxes and are watching the kilometers and meters. So each time a value changes, we do some calculation.

B4X:
vue.setdata("kilometers", "0")
    vue.Setdata("meters", "0")
    
    '
    Dim inpk As VMElement = vue.CreateINPUT("").settype("text").setvmodel("kilometers")
    Dim inpm As VMElement = vue.createinput("").settype("text").Setvmodel("meters")
    
    div.AddComponent(inpk.tostring)
    div.AddComponent(inpm.tostring)
    
    vue.SetWatch("kilometers", True, True, Me, "kilometers1")
    vue.SetWatch("meters", True, True, Me, "meters1")

Remember: For re-active states, these need to be initialized first, ALL THE TIME for the first time!

So each time the "values" for kilometers and meters as defined by the vmodels change, we need to chall kilometers1 and meters1 callbacks.

These receive the entered values and then you can process them.

B4X:
Sub kilometers1(val As Object)
    Dim dmeters As Int = val * 1000
    vue.setdata("kilometers", val)
    vue.setdata("meters", dmeters)
End Sub

Sub meters1(val As Object)
    Dim dkilometers As Int = val / 1000
    vue.setdata("kilometers", dkilometers)
    vue.setdata("meters", val)
End Sub

vue.setdata is updating the view state and vue.getstate retries the stored values. For these watches, we do some calculations and assign the values to the view state, which in turn updates the vmodel i.e. the values in the input boxes.

We will now explore this with actual Vuetify components and routers. This covers some VueJS functionality that is useful.

Enjoy!
 
Top